PowerShell Function: Get-Sysinternals

    ##--------------------------------------------------------------------------
    ##  FUNCTION.......:  Get-Sysinternals
    ##  PURPOSE........:  Downloads or updates the Sysinternal Utilities.
    ##  REQUIREMENTS...:  PowerShell 2.0
    ##  NOTES..........:  
    ##--------------------------------------------------------------------------
    Function Get-Sysinternals {
        <#
        .SYNOPSIS
         Downloads or updates the Sysinternals Utilities. For examples type:
         Get-Help Get-Sysinternals -examples
        .DESCRIPTION
         The Get-Sysinternals Function uses file timestamps to determine if 
         there are updates or (optionally) new utilities available from 
         live.sysinternals.com, if there are they will be downloaded and saved 
         in the specified directory.
         This function will also log all output to whatever directory is 
         specified by the -Path parameter (by default this is 
         "c:\admin\tools\logfile.txt").
        .PARAMETER <Path>
         This optional parameter defines the location of your Sysinternals 
         Utilities, or where they will be saved if none are present. The default
         value is "c:\admin\tools". If you specify a path that does not exist, 
         it will be created. If a trailing slash is used in the path, the 
         operation will fail.
        .PARAMETER <getnew>
         This optional parameter will get any utilities that are available on 
         live.sysinternals.com, which do not exist in the specified directory.
        .EXAMPLE
         C:\PS>Get-Sysinternals
         
         This example will check the directory "c:\admin\tools" for existing 
         Sysinternals utilities and update any with newer verisons.
         
        .EXAMPLE
         C:\PS>Get-Sysinternals c:\sysinternals
         
         This example will do the same thing as Example 1, but using the 
         "c:\sysinternals" folder.
         
        .EXAMPLE
         C:\PS>Get-Sysinternals c:\sysinternals -verbose
         
         This example will do the same thing as Example 2, but will also write 
         verbose output to the console.
         
        .EXAMPLE
         C:\PS>Get-Sysinternals c:\sysinternals -getnew -verbose
         
         This example will do the same thing as Example 3, but will also 
         download any utilities that are available on live.sysinternals.com, 
         but which do not exist in the specified path.
        
        .NOTES
         NAME......:  Get-Sysinternals
         AUTHOR....:  Joe Glessner
         LAST EDIT.:  24MAY12
         CREATED...:  11APR11
        .LINK
         https://joeit.wordpress.com/
        #>
        [CmdletBinding()]
        Param(
            [Parameter(Mandatory=$False, 
                        Position=0,                           
                        ValueFromPipeline=$false,             
                        ValueFromPipelineByPropertyName=$false)]
            [String]$Path = "c:\admin\tools",
            [Switch]$GetNew
        )#END: Param
        $SysIn = "\\live.sysinternals.com\tools"
        If ($PSBoundParameters['Verbose']) {
            net use $SysIn /persistent:no;
            New-PSDrive -Name SYS -PSProvider filesystem -Root $SysIn
        }#END: If ($PSBoundParameters['Verbose'])
        Else {
            Net Use $SysIn /persistent:no | Out-Null;
            New-PSDrive -Name SYS -PSProvider filesystem -Root $SysIn | out-null
        }#END: Else
        If(!(Test-Path -Path $Path -PathType Container)) {
            $null = New-Item -Type Directory -Path $Path -Force
        }#END: If(!(Test-Path...
        $log = join-path $Path "logFile.txt"
        Write-Verbose "Logging to: $log"
        Add-Content -force $log -value "`n`n[$(get-date)]Update started..."
        Get-ChildItem SYS: -recurse | ForEach {
            $fileName = $_.name
            $localFile = join-path $Path $_.name
            $exist = test-path $localFile
            $msgNew = "  ** New utility found: $fileName , downloading..."
            $msgUpdate = "  ** Update found for: $fileName , downloading..."
            $msgNoChange = "    No update for: $fileName"
            If($exist) {
                If($_.lastWriteTime -gt (Get-Item $localFile).lastWriteTime) {
                    Copy-Item $_.fullname $Path -force
                    Write-Verbose $msgUpdate
                    Add-Content -force $log -value $msgUpdate
                 }#END: ($_.lastWriteTime...
                Else {
                    Add-Content $log -force -value $msgNoChange
                    Write-Verbose $msgNoChange
                 }#END: Else
            }#END: If($exist)
            If($GetNew) {
                If(!($exist)) {
                    If($_.extension -eq ".exe") {
                          Write-Verbose $msgNew
                          Add-Content -force $log -value $msgNew
                     }#END: If($_.extension -eq ".exe")
                    Copy-Item $_.fullname $Path -force
                }#END: If(!($exist))
            }#END: If($GetNew)
        }#END: Get-ChildItem SYS: -recurse | ForEach
        Write-Verbose "[$(get-date)]Update completed."
        Add-Content -force $log -value "`n`n[$(get-date)]Update completed."
    }#END: Function Get-Sysinternals

 

Advertisements

PowerShell Function: Get-MD5Checksum

    ##--------------------------------------------------------------------------
    ##  FUNCTION.......:  Get-MD5Checksum
    ##  PURPOSE........:  Generates an MD5 checksum for the specified file.
    ##  REQUIREMENTS...:  PowerShell v2
    ##  NOTES..........:  
    ##--------------------------------------------------------------------------
    Function Get-MD5Checksum {
        <#
        .SYNOPSIS
         Generates an MD5 checksum for the specified file.
        .DESCRIPTION
         This function uses the 
         System.Security.Cryptography.MD5CryptoServiceProvider .NET class to
         generate and retun an MD5 checksum for the specified file.
        .PARAMETER FileName
         The filename including path for which to generate the MD5 sum.

         ALIAS: -f
        .EXAMPLE
         C:\PS>Get-MD5Checksum c:\test.txt

         This will return an MD5 checksum for the file c:\test.txt

        .EXAMPLE
         C:\PS>"C:\TEST\test.csv" | Get-MD5Checksum

         This will also return an MD5 checksum for the file c:\test.txt, passing
         the FileName to the function using pipelining.

        .NOTES
         NAME......:  Get-MD5Checksum
         AUTHOR....:  Joe Glessner
         LAST EDIT.:  14MAY12
         CREATED...:  11APR08
        .LINK
         https://joeit.wordpress.com/
        #>

        Param([Parameter(Mandatory = $True,
            ValueFromPipeLine = $True,
            Position = 0)]
            [Alias('f')]
            [String]$FileName
        )#END: Param

        $MD5 = New-Object System.Security.Cryptography.MD5CryptoServiceProvider
        If([System.IO.File]::Exists($FileName)) {
            $FileStream = New-Object System.IO.FileStream($FileName,`
            [System.IO.FileMode]::Open,[System.IO.FileAccess]::Read,`
            [System.IO.FileShare]::ReadWrite)
            [byte[]]$ByteSum = $MD5.ComputeHash($FileStream)
            $Sum = ([System.Bitconverter]::ToString($ByteSum)).Replace("-","")
            $FileStream.Close()
        }#END: If([System.IO.File]::Exists($fileName))
        Else {
            $Sum = "ERROR: $FileName Not Found"
        }#END: Else
        Return $Sum
    }#END: Function Get-MD5Checksum

Admin’s Arsenal: iPhone Configuration Utility

Jesus holding iPhone I got an iPhone in 2009. I like it, it does what I need it to do. I’m not with the fanboi crowd that thinks that Steve Jobs was a saint, and the iPhone is the holy grail of cell phones. The thing has problems. The fact that I still cannot define a time that I do not want the phone to ring or vibrate, or only ring for specific callers (without jailbreaking) is pretty silly.

But it is still light years ahead of a Blackberry, and in my opinion far easier to use and maintain than an Android device.

All that aside, iOS is here, and our users want it. I’ve got about 10 users with iOS devices, and it’s spreading. I do not support enough mobile devices to justify a Mobile Device Management solution, but that doesn’t mean that I am forced to manage them all by hand either.

Some time ago Apple released the iPhone Configuration Utility (available here for both Mac and Windows computers), designed for exactly my use case.

You’ll notice that Apple has quite a bit of information available at that link, including an MDM solution specifically for iOS devices (which unfortunately is OSX only). Not bad, I’ll tip my hat to Cupertino on that, they aren’t ignoring the Windows people (for once).

The iPhone Configuration utility allows you to define profiles and configure settings for iOS devices (it works fine with iPads).

Let’s take a look at the interface (click the image to see the full size versions):

iPhone Configuration Utility interface

iPhone Configuration Utility interface

 

Note at the bottom there the setting to control when the profile can be removed from the phone. I would suggest that you choose the “With Authentication” setting, as you never know when you might need to remove the profile, and you don’t want users screwing around in there and accidentally removing the security policy requiring a passcode for compliance reasons (or just general security). Speaking of Passcodes:

Passcode policy

Passcode Policy settings

 

You can see here that you’ve got pretty granular passcode settings available, which is great because if Apple is known for doing one thing right, it sure isn’t security. If you happen to be in an environment where you need to disable certain settings, the Restrictions policy settings have you pretty well covered:

Restriction Policy Settings

Restriction Policy Settings

 

Which is great if you need to control things like disabling Siri when the device is locked. The utility also gives you the ability to define Wi-Fi networks that the iOS device is allowed to connect to:

Wi-Fi Policy Settings

Wi-Fi Policy Settings

 

This is actually pretty handy, you don’t need to give out wi-fi passwords, and you can isolate mobile devices as needed. If for some strange reason you want to allow users to connect their phones to your VPN, there is provision for that as well:

VPN Policy Settings

VPN Policy Settings

 

This is great for me personally, as I can use this to allow secure connection to our Spiceworks install, as well as remote desktop for emergencies. And of course we need email:

Exchange ActiveSync Policy Settings

Exchange ActiveSync Policy Settings

 

Pretty standard stuff from here out.

Here’s how I use this:

I have one company wide device security policy that gets installed on all devices. This is basically a passcode and screen lock policy that also disables Siri when the phone is locked. These are company devices, with confidential company information on them. I know it’s inconvenient for you to have to enter a 4 digit passcode when you want to use your phone, but tough. Don’t like it? I’ll remove it when there is no longer any company data on the phone, and that includes email and contacts that have employee’s home contact information in them.

I have one email profile that is basically a shared contacts box that get’s installed on every device.

Each user has an email policy that configures access to their work email.

I have a VPN profile that allows me to VPN into our network from my phone, but no one else has this capability.

This is great because in the 3+ years I’ve had an iPhone, I’ve had to replace or wipe the device at least 10 times. They’re not the most hearty of devices (that crown is still held by the mighty BlackBerry, which I know from experience can survive being thrown from the second floor of a building into parking lot during a torrential downpour), and water is like antimatter to them.

Now when I need to change hardware, or reload the device I simply email the four profiles to myself, and bingo all of my email settings are squared away in seconds (iCloud makes this super easy anyway, but it can take a while to get it working).

 

 

 

PowerShell Function: Reset-Module

    ##--------------------------------------------------------------------------
    ##  FUNCTION.......:  Reset-Module
    ##  PURPOSE........:  Removes and then imports the specified PowerShell 
    ##                    Module.
    ##  REQUIREMENTS...:  The Module must be registered with the shell.
    ##  NOTES..........:  
    ##--------------------------------------------------------------------------
    Function Reset-Module {
        <#
        .SYNOPSIS
         Removes and then re-imports the specified PowerShell Module.
         For examples type:
         Help Reset-Module -examples
        .DESCRIPTION
         Removes and then re-imports the specified PowerShell Module.
        .PARAMETER ModuleName
         The Name of the Module to reload.
        .EXAMPLE
         C:\PS>Reload-Module TroubleshootingPack

         This example will reload the TroubleshootingPack module. This example
         will produce no visible output.

        .EXAMPLE
         C:\PS>Reload-Module TroubleshootingPack -verbose

         This example does the same thing as Example 1, but will also write 
         verbose output to the console.

        .NOTES
         NAME......:  Reset-Module
         AUTHOR....:  Joe Glessner
         LAST EDIT.:  19MAY11
         CREATED...:  19MAY11
        .LINK
         about_Modules
         https://joeit.wordpress.com/
        #>
        [CmdletBinding()]             
            Param (                        
                [Parameter(Mandatory=$True, 
                    #ValueFromPipeline=$True,
                    #ValueFromPipelineByPropertyName=$True,
                    Position=0)]  
                [String]$ModuleName
                )#End Param
        Write-Verbose "Removing Module $ModuleName"
        Remove-Module $ModuleName
        Start-Sleep -s 1
        Write-Verbose "Importing Module $ModuleName"
        Import-Module $ModuleName
    }#END: Module Reset-Module

PowerShell Function: Set-RunOnce

    ##--------------------------------------------------------------------------
    ##  FUNCTION.......:  Set-RunOnce
    ##  PURPOSE........:  Changes the RunOnce registry key to run whatever is 
    ##                    specified by the user.
    ##  REQUIREMENTS...:  Administrator credentials are needed to write to the 
    ##                    HKLM registry hive.
    ##  NOTES..........:  
    ##--------------------------------------------------------------------------
    Function Set-RunOnce {
        <#
        .SYNOPSIS
         Changes the RunOnce registry key to run whatever is specified by the 
         user.
        .DESCRIPTION
         This function writes subkeys to 'HKLM:\SOFTWARE\Microsoft\Windows\
         CurrentVersion\RunOnce'. 
         
         If run without parameters, this function will default RunOnce to run
         notepad.exe on the next reboot.
         
         By default anything written to this key will not run in Safe Mode, and 
         will not be run again if the operation fails.
        .PARAMETER Description
         This is the name of the subkey that will be written to RunOnce. This 
         can be any text, as long as there are no spaces in it.
         Alias..: -name, -n
        .PARAMETER FileToRun
         The full name (including path) of the file to run after reboot.
         Alias..: -file, -f
        .PARAMETER PassScriptToPowerShell
         In some instances it is necessary to specify the full path to the
         PowerShell executable when using PowerShell scripts with RunOnce. This
         Switch alters the FileToRun parameter to include this path.
         Alias..: -UsePoSh, -p
        .PARAMETER SafeMode
         This Switch will prepend a '*' character to the -FileToRun parameter,
         which will allow RunOnce to function in Safe Mode.
         Alias..: -safe, -s
        .PARAMETER Defer
         This Switch will prepend a '!' character to the -FileToRun parameter,
         which will delay the deletion of the RunOnce value until the command
         has completed. As a result, if a RunOnce operation does not run 
         properly, the associated program will be asked to run at the next boot.
         Alias..: -d
        .EXAMPLE
         C:\PS>Set-RunOnce
         
         This example will write a subkey to RunOnce named "Notepad" with a 
         REG_SZ value of 'notepad.exe', causing notepad.exe to run at the next 
         reboot.
         
        .EXAMPLE
         C:\PS>Set-RunOnce TestName c:\test.cmd
         
         This example will write a subkey to RunOnce named "TestName" with a 
         REG_SZ value of 'c:\test.cmd', causing test.cmd to run at the next 
         reboot.
         
        .EXAMPLE
         C:\PS>Set-RunOnce ps1 c:\a.ps1 -UsePoSh
         
         This example will write a subkey to RunOnce named "ps1" with a REG_SZ 
         value of 
         'C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe "c:\a.ps1"',
         causing PowerShell to run the a.ps1 script at the next reboot. 
         The use of the -PassScriptToPowerShell parameter (or it's aliases 
         -UsePoSh or -u) is not strictly necessary to get PowerShell scripts to 
         work with RunOnce, it will depend on how you have configured your 
         system to handle the execution of PowerShell scripts. When in doubt, 
         use this parameter to ensure that the script will run.
         
         NOTE:
         PowerShell's Execution Policy must be set to allow scripts to run for
         this to work.
        .EXAMPLE
         C:\PS>"c:\a.ps1" | Set-RunOnce ps1 -p
         
         This example does the same thing as EXAMPLE 3, but uses pipelining to
         pass the -FileToRun parameter, and uses the -p alias for the
         -PassScriptToPowerShell parameter.
         
        .NOTES
         NAME......:  Set-RunOnce
         AUTHOR....:  Joe Glessner
         LAST EDIT.:  10JUN11
         CREATED...:  11APR11
        .LINK
         https://joeit.wordpress.com/
        .LINK
         http://support.microsoft.com/kb/314866/EN-US
        .LINK
         http://msdn.microsoft.com/en-us/library/aa376977%28v=vs.85%29.aspx
        #>
        [CmdletBinding()]
        Param(
            [Parameter(ValueFromPipeline=$False,
                Position=0,
                Mandatory=$False)]
            [Alias("name","n")]
            [String]$Description="Notepad",
            [Parameter(ValueFromPipeline=$True,
                Position=1,
                Mandatory=$False)] 
            [Alias("file","f")]
            [String]$FileToRun="notepad.exe",
            [Alias("UsePosh","p")]
            [Switch]$PassScriptToPowerShell,
            [Alias("safe","s")]
            [Switch]$SafeMode,
            [Alias("d")]
            [Switch]$Defer
        )#END: Param
        Write-Verbose "Verifying user context..."
        $currentPrincipal = New-Object Security.Principal.WindowsPrincipal( `
        [Security.Principal.WindowsIdentity]::GetCurrent() ) 
        If ($currentPrincipal.IsInRole( `
            [Security.Principal.WindowsBuiltInRole]::Administrator )) { 
            Write-Verbose "PowerShell is running in Administrator context."
        }#END: If ($currentPrincipal.IsInRole(...
        Else { 
            Write-Warning "Set-RunOnce requires Administrator credentials."
            Write-Warning "Elevate PowerShell before retrying the operation."
            Write-Warning "No changes were made."
            Break
        }#END: Else 
        $RegistryKey = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce'
        $PoSh = "C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe"
        Write-Verbose "Marking current location..."
        Push-Location
        Write-Verbose "Moving to $RegistryKey..."
        Set-Location -Path $RegistryKey
        If($PassScriptToPowerShell) {
            $char0 = [char] '"'
            $char1 = [char] "'"
            $FullPath = $PoSh + " " + $char0 + $FileToRun + $char0
            Write-Verbose "Setting RunOnce to use PowerShell..."
            $FileToRun = $FullPath
        }#END: If($PassScriptToPowerShell)
        ElseIf($SafeMode) {
            $AltPath = "*" + $FileToRun
            Write-Verbose "Setting RunOnce to work in SafeMode..."
            $FileToRun = $AltPath
        }#END: ElseIf($SafeMode)
        If($Defer) {
            $AltPath = "!" + $FileToRun
            Write-Verbose "Setting to persist if $FileToRun fails to run ..."
            $FileToRun = $AltPath
        }#END: If($Defer)
        Write-Verbose "Creating RunOnce subkey for $Description..."
        Set-ItemProperty -Path . -Name $Description -Value $FileToRun
        Write-Verbose "Returning to marked location..."
        Pop-Location
    }#END: Function Set-RunOnce

 

PowerShell Function: Elevate-Process (like SUDO for PowerShell)

    ##--------------------------------------------------------------------------
    ##  FUNCTION.......:  Grant-ElevatedProcess
    ##  PURPOSE........:  Runs commands with an elevated security context when 
    ##                    UAC is enabled.
    ##  REQUIREMENTS...:  PowerShell v2
    ##  NOTES..........:  
    ##--------------------------------------------------------------------------
    Function Grant-ElevatedProcess {
        <#
        .SYNOPSIS
         Runs commands with an elevated security context when UAC is enabled.
        .DESCRIPTION
         Full description of function
        .PARAMETER Arguments
         The command to run elevated. Anything typed after the function name 
         will be processed.

        .EXAMPLE
         C:\PS>Grant-ElevatedProcess ipconfig /flushdns
         
         This will prompt for elevation, and then run a command that will clear 
         the DNS resolver cache on the local machine.
         
        .NOTES
         NAME......:  Grant-ElevatedProcess
         AUTHOR....:  Joe Glessner
         LAST EDIT.:  10FEB12
         CREATED...:  11APR11
         
         Based on code posted by weestro at http://weestro.blogspot.com/
        .LINK
         https://joeit.wordpress.com/
        .LINK
         http://weestro.blogspot.com/2009/08/sudo-for-powershell.html
        #>
        $File, [String]$Arguments = $Args;
        $Process = new-object System.Diagnostics.ProcessStartInfo $File;
        $Process.Arguments = $Arguments;
        $Process.Verb = "RunAs";
        $Process.WorkingDirectory = Get-Location;
        [System.Diagnostics.Process]::Start($Process);
    }#END: Function Grant-ElevatedProcess
    Set-Alias -name sudo -value Grant-ElevatedProcess

 

PowerShell Function: Convert-WordToPDF

    ##--------------------------------------------------------------------------
    ##  FUNCTION.......:  Convert-WordToPDF
    ##  PURPOSE........:  Converts Word documents to PDF files.
    ##  REQUIREMENTS...:  PowerShell v2, Word 2007
    ##  NOTES..........:  This has been tested with Word 2010, it may also work
    ##                    with Word 2003 but has not been tested.
    ##--------------------------------------------------------------------------
    Function Convert-WordToPDF {
        <#
        .SYNOPSIS
         Converts Word documents to PDF files.

         For examples, type:
         Help Convert-WordToPDF -examples
        .DESCRIPTION
         This function uses the Word.Application COM Object to convert .doc or
         .docx files to PDF files. By default this function works on .doc files,
         If the file to be converted is a .docx file, use the -docx switch.
        .PARAMETER Path
         The full path (including file name) to the document to be converted.
        .PARAMETER Docx
         This optional switch allows the conversion of .docx files to PDF. If 
         this switch is omitted, and a .docx file is specified, the Function 
         will still convert the file, however the resulting file will have an 
         extension of .pdfx (you just need to delete the "x" off the end, and
         the file will open fine).
        .EXAMPLE
         C:\PS>Convert-WordToPDF c:\test.doc

         This example will convert the file c:\test.doc to a PDF file. The 
         resulting file will be saved to c:\test.pdf (the .doc file will not be 
         deleted).

        .EXAMPLE
         C:\PS>Convert-WordToPDF c:\test.docx -docx

         This example will convert the file c:\test.docx to a PDF file. The 
         resulting file will be saved to c:\test.pdf (the .docx file will not be
         deleted).

        .EXAMPLE
         C:\PS>"c:\test.doc" | Convert-WordToPDF

         This example will do the same thing as EXAMPLE 1, showing how to pass
         a document to the function for conversion using pipelining.

        .NOTES
         NAME......:  Convert-WordToPDF
         AUTHOR....:  Joe Glessner
         LAST EDIT.:  08JUN11
         CREATED...:  11APR11

        .LINK
         https://joeit.wordpress.com/
        .LINK
         http://msdn.microsoft.com/en-us/library/bb238158%28v=office.12%29.aspx
        #>
        [CmdletBinding()]
        Param(
            [Parameter(ValueFromPipeline=$True,
                Position=0,
                Mandatory=$True,
                HelpMessage="The filename and path for the Word document.")] 
            [ValidateScript({Test-Path (split-path $_)})]
            [String]$Path,
            [Switch]$Docx
        )#END: Param
        Write-Verbose "Setting Word constants..."
        $wdFormatPDF = [ref] 17
        Write-Verbose "Connection to the Word.Application COM Object..."
        $Word = New-Object -Com Word.Application
        $Word.Visible = $False
        Write-Verbose 'To enable debugging set $Word.Visible = $True'
        If (!(test-path $Path)) { 
            "File $Document does not exist!"
            Break 
        }#END: If (!(test-path $Path))
        Write-Verbose "Opening document $Path..."
        $existingDoc=$word.Documents.Open($Path)
        Write-Verbose "Changing file extension to '.pdf'..."
        If($Docx) {
            $SaveAsPath = $Path.Replace('.docx','.pdf')
        }#END: If($Docx)
        Else {
            $SaveAsPath = $Path.Replace('.doc','.pdf')
        }#END: Else
        If(test-path $SaveAsPath) { 
            Write-Verbose "Delete the output file if it already exists..."
            rm $SaveAsPath
        }#END: If(test-path $saveaspath)
        Write-Verbose "Saving file $SaveAsPath..."
        $ExistingDoc.SaveAs( [ref] $SaveAsPath, $wdFormatPDF )
        Write-Verbose "Closing document $Path..."
        $existingDoc.Close()
        Write-Verbose "Exiting Word..."
        $Word.Quit()
    }#END: Function Convert-WordToPDF

%d bloggers like this: