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).

 

 

 

Advertisements

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

PowerShell Function: Find-Hotfix

Every now and then you’ll need to verify whether or not a given hotfix is installed on a particulat computer (or group of computers). This function takes all the work out of that task.

    ##--------------------------------------------------------------------------
    ##  FUNCTION.......:  Find-Hotfix
    ##  PURPOSE........:  Finds computers with a specified Microsoft Hotfix
    ##                    installed.
    ##  REQUIREMENTS...:  PowerShell v2.0
    ##  NOTES..........:  
    ##--------------------------------------------------------------------------
    Function Find-Hotfix {
        <#
        .SYNOPSIS
         Finds computers with a specified Microsoft Hotfix installed.

        .DESCRIPTION
         This function reads a list of computernames (one per line), checks each
         to determine if the specified hotfix is installed, and displays a list
         of all computers and the status of the hotfix for that computer.
        .PARAMETER FileName
         Full path and filename of the file containing a list of computers to
         check (one computer name per line). THis is a mandatory parameter. If
         you omit it, you will be prompted to enter a value before the function
         continues.
        .PARAMETER KB
         The KB number of the hotfix to check for (just the number). This is a
         mandatory parameter. If you omit it, you will be prompted to enter a
         value before the function continues.

        .EXAMPLE
         C:\PS>Find-Hotfix c:\list.txt 2564958

         This example will check all computers listed in the file "c:\list.txt"
         for hotfix KB2564958.

         Sample output:
         Wkstn01    HOTFIX NOT FOUND
         Wkstn02    Security Update
         Wkstn03    HOTFIX NOT FOUND
         Svr01      Security Update
         Svr02      Security Update

        .EXAMPLE
         C:\PS>'c:\list.txt' | Find-Hotfix -KB:2564958

         This example does the same thing as Example 1, but the list of
         computers to check is being passed to the Function using pipelining.

        .NOTES
         NAME......:  Find-Hotfix
         AUTHOR....:  Joe Glessner
         LAST EDIT.:  21MAR12
         CREATED...:  10APR11
        .LINK
         https://joeit.wordpress.com/
        #>

        [CmdletBinding()]             
                Param (                        
                    [Parameter(Mandatory=$True,
                        ValueFromPipeline=$True,
                        Position=0)]  
                    [Alias('file,f')]
                    [String]$FileName,
                    [Parameter(Mandatory=$True,
                        ValueFromPipeline=$False,
                        Position=1)]
                    [String]$KB
                )#End Param
        $ErrorActionPreference = "SilentlyContinue"
        $ComputerNames = Get-Content $FileName
        $KBN = "kb" + $KB

        ForEach ($Computer In $ComputerNames) {
            $StrQuery = "select * from win32_pingstatus where address = '" +
            $Computer + "'"
            $WMI = Get-WMIObject -query $StrQuery
            If ($wmi.statuscode -eq 0) {
                $CheckKB = GWMI Win32_QuickFixEngineering -computer $Computer |
                Where-Object {$_.hotfixid -eq $KBN} |
                Select-Object hotfixid, description
                    If ($CheckKB.hotfixid -eq $KBN) {
                        Write-Host -f green $Computer `
                        "`t" $CheckKB.Description "`r"
                    }#END: If ($CheckKB.hotfixid -eq $KBN)
                    Else {
                        Write-Host -f red $Computer `
                        "`t" "HOTFIX NOT FOUND" "`r"
                    }#END: Else
            }#END: If ($wmi.statuscode -eq 0)
            Else {
                Write-Host -f yellow $Computer "`t" "Ping failed!" "`r"
                }#END: Else
        }#END: ForEach ($Computer In $ComputerNames)
    }#END: Function Find-HotFix

PowerShell Function: Invoke-Sound

    ##--------------------------------------------------------------------------
    ##  FUNCTION.......:  Invoke-Sound
    ##  PURPOSE........:  Beep the system speaker.
    ##  REQUIREMENTS...:  PowerShell v2
    ##  NOTES..........:  
    ##--------------------------------------------------------------------------
    Function Invoke-Sound {
        <#
        .SYNOPSIS
         Beep the system speaker.
        .DESCRIPTION
         This function gives the user a wide variety of control over the system
         speaker (and can optionally be used to play a few Windows sounds
         through the regular speakers).
        .PARAMETER Frequency
         The pitch of the beep (larger numbers is a higher pitch). Defaults to
         1000.

         ALIAS: -f
        .PARAMETER Time
         The length of the beep in miliseconds (1000 = 1 second). Defaults to
         300ms.

         ALIAS: -t
        .PARAMETER Beeps
         The number of beeps to execute (defaults to one).

         ALIAS: -b
        .PARAMETER Sub
         This optional Switch will set the Frequency to 100.

         ALIAS: -s
        .PARAMETER Low
         This optional Switch will set the Frequency to 500.

         ALIAS: -l
        .PARAMETER Medium
         This optional Switch will set the Frequency to 2000.

         ALIAS: -m
        .PARAMETER High
         This optional Switch will set the Frequency to 5000.

         ALIAS: -h
        .PARAMETER Exclamation
         This optional switch will play the "exclamation" system sound using the
         PC speakers (not the system speaker).

         ALIAS: -ex
        .PARAMETER Asterisk
         This optional switch will play the "asterisk" system sound using the
         PC speakers (not the system speaker).

         ALIAS: -as
        .PARAMETER Hand
         This optional switch will play the "hand" system sound using the PC
         speakers (not the system speaker).

         ALIAS: -ha
        .PARAMETER Vader
         Plays part of the Imperial March using the System Speaker.
        .EXAMPLE
         C:\PS>Invoke-Sound

         This Example will play a 300ms beep from the system speaker with the
         frequency set to 1000.

        .EXAMPLE
         C:\PS>Invoke-Sound 2000 5000

         This Example will play a 5 second beep from the system speaker with the
         frequency set to 2000.

        .EXAMPLE
         C:\PS>Invoke-Sound -asterisk

         This Example will play the "asterisk" system sound through the PC
         speakers (not the system speaker).

        .EXAMPLE
         C:\PS>Invoke-Sound -beeps:5

         This will play 5 beeps from the system speaker using the default
         frequency of 1000 and time of 300ms.

        .EXAMPLE
         C:\PS>Invoke-Sound -vader

         Plays a section of the Imperial March from Star Wars :)

        .NOTES
         NAME......:  Invoke-Sound
         AUTHOR....:  Joe Glessner
         LAST EDIT.:  27MAR12
         CREATED...:  12FEB10
        .LINK
         https://joeit.wordpress.com/
        #>

        Param([Parameter(Mandatory = $False,
            Position = 0)]
            [Alias('f')]
            [Int]$Frequency = 1000,
            [Parameter(Mandatory = $False,
            Position = 1)]
            [Alias('t')]
            [Int]$Time = 300,
            [Alias('b')]
            [Int]$Beeps = 1,
            [Alias('s')]
            [Switch]$Sub,
            [Alias('l')]
            [Switch]$Low,
            [Alias('m')]
            [Switch]$Medium,
            [Alias('h')]
            [Switch]$High,
            [Alias('ex')]
            [Switch]$Exclamation,
            [Alias('as')]
            [Switch]$Asterisk,
            [Alias('ha')]
            [Switch]$Hand,
            [Switch]$Vader
        )#END: Param
        If($Sub) {
            $Frequency = 100
        }#END: If($Sub)
        If($Low) {
            $Frequency = 500
        }#END: If($Low)
        IF($Medium) {
            $Frequency = 2000
        }#END: IF($Meduim)
        If($High) {
            $Frequency = 5000
        }#END: If($High)
        If($Exclamation) {
            [system.media.systemsounds]::Exclamation.play()
            Break;
        }#END: If($Exclamation)
        If($Asterisk) {
            [system.media.systemsounds]::Asterisk.play()
            Break;
        }#END: If($Asterisk)
        If($Hand) {
            [system.media.systemsounds]::Hand.play()
            Break;
        }#END: If($Hand)
        If($Vader) {
            [console]::beep(340,500)
            [console]::beep(340,500)
            [console]::beep(340,500)
            [console]::beep(249,350)
            [console]::beep(423,150)
            [console]::beep(340,500)
            [console]::beep(249,350)
            [console]::beep(423,150)
            [console]::beep(340,1000)
            [console]::beep(559,500)
            [console]::beep(559,500)
            [console]::beep(559,500)
            [console]::beep(598,350)
            [console]::beep(423,150)
            [console]::beep(315,500)
            [console]::beep(249,350)
            [console]::beep(423,150)
            [console]::beep(340,1000)
        }#END: If($Vader)
        ELSE {
            1..$Beeps | %{[System.Console]::Beep($Frequency,$Time)}
        }#END: Else
    }#END: Function Invoke-Sound

%d bloggers like this: