Quantcast
Channel: PowerShell App Deployment Toolkit
Viewing all 2341 articles
Browse latest View live

New Post: New to the PDT


New Post: Create new folder using New-Item

$
0
0
I am a beginner of powershell, came across this little app and have started to use it. It works well for me until I have to do something a little outside the box then it gets a bit tricky.

I came across this post:
https://psappdeploytoolkit.codeplex.com/discussions/471396

Which kinda what I was looking for accept my files are going into Appdata\

I tried just using it and modifying it for my needs and it does not create the folder, but it attempts to copy the file. Because it continues to go without stopping, it installs the app.

I need to be able to create the folder in \AppData\Roaming\Folder1\Folder2

Then copy an .xml file from the Appdeploy Files folder to \AppData\Roaming\Folder1\Folder2

Then install the .msi file (which installs fine)

I tried:
New-Item -ItemType Directory -Force -Path "C:\Users\$($user.Name)\AppData\Roaming\Folder1\Folder2\"
    Copy-File -Path "$dirFiles\config_update.xml" -Destination "C:\Users\$($user.Name)\AppData\Roaming\Folder1\Folder2\config_update.xml"
But that didn't work properly.

Then I tried to modify the one in the post to create the folder:
    If (!(Test-Path -Path "C:\Users\$($user.Name)\AppData\Roaming\Folder1\Folder2\" -ErrorAction SilentlyContinue )) { New-Item "C:\Users\$($user.Name)\AppData\Roaming\Folder1\Folder2\" -Type Directory -ErrorAction SilentlyContinue | Out-Null }
But it also does not work. I am sure this is something simple and I Will continue to try multiple things, but thought I would ask while I am trying/learning.
thanks

New Post: Create new folder using New-Item

$
0
0
I figured it out...

My issue was the $($user.Name). I changed it to $env:Username and everything looks to be working.

So now I have:
If (!(Test-Path -Path "C:\Users\$env:Username\AppData\Roaming\Folder1\Folder2\" -ErrorAction SilentlyContinue )) { New-Item "C:\Users\$env:Username\AppData\Roaming\Folder1\Folder2\" -Type Directory -ErrorAction SilentlyContinue | Out-Null }
Copy-File -Path "$dirFiles\config_update.xml" -Destination "C:\Users\$env:Username\AppData\Roaming\Folder1\Folder2\config_update.xml"

Commented Unassigned: -Patch Parameter for Execute-MSI [83]

$
0
0
Could you please implement a -Patch parameter similiar to the -Transform parameter?

I do not want to override the default switches everytime ive to specify patches.

e.g For Adobe Products its not recommended to slipstream the MSPs into the main MSI.

Regards,
Fabio
Comments: This parameter already exists.

New Post: Show-InstallationRestartPrompt only for Exit Code 3010?

$
0
0
Hello,

I've just started using the PSADT and it's really great, but I've ran into a slight issue. I would like to use Show-InstallationRestartPrompt, but only if Windows Installer returns the 3010 exit code and a restart is actually needed. Is there anyway to catch the exit code or another way to do this?

I don't see anything in the documentation, but perhaps I've overlooked it.

New Post: Help! Execute-Process passing arguments to an MSI with a Transform

$
0
0
It wasn't the switches because I tried both actually. what it was is I was trying to enter the full path to the transform when it just needed the transform itself. I see your point about not using a transform with an exe though.

New Post: Show-InstallationRestartPrompt only for Exit Code 3010?

$
0
0
I use a function to check for pending reboots and then If/Else on that. Here's the function I use:
Function Get-PendingReboot 
{ 
<# 
.SYNOPSIS 
    Gets the pending reboot status on a local or remote computer. 
 
.DESCRIPTION 
    This function will query the registry on a local or remote computer and determine if the 
    system is pending a reboot, from either Microsoft Patching or a Software Installation. 
    For Windows 2008+ the function will query the CBS registry key as another factor in determining 
    pending reboot state.  "PendingFileRenameOperations" and "Auto Update\RebootRequired" are observed 
    as being consistant across Windows Server 2003 & 2008. 
   
    CBServicing = Component Based Servicing (Windows 2008) 
    WindowsUpdate = Windows Update / Auto Update (Windows 2003 / 2008) 
    CCMClientSDK = SCCM 2012 Clients only (DetermineIfRebootPending method) otherwise $null value 
    PendFileRename = PendingFileRenameOperations (Windows 2003 / 2008) 
 
.PARAMETER ComputerName 
    A single Computer or an array of computer names.  The default is localhost ($env:COMPUTERNAME). 
 
.PARAMETER ErrorLog 
    A single path to send error data to a log file. 
 
.EXAMPLE 
    PS C:\> Get-PendingReboot -ComputerName (Get-Content C:\ServerList.txt) | Format-Table -AutoSize 
   
    Computer CBServicing WindowsUpdate CCMClientSDK PendFileRename PendFileRenVal RebootPending 
    -------- ----------- ------------- ------------ -------------- -------------- ------------- 
    DC01           False         False                       False                        False 
    DC02           False         False                       False                        False 
    FS01           False         False                       False                        False 
 
    This example will capture the contents of C:\ServerList.txt and query the pending reboot 
    information from the systems contained in the file and display the output in a table. The 
    null values are by design, since these systems do not have the SCCM 2012 client installed, 
    nor was the PendingFileRenameOperations value populated. 
 
.EXAMPLE 
    PS C:\> Get-PendingReboot 
   
    Computer       : WKS01 
    CBServicing    : False 
    WindowsUpdate  : True 
    CCMClient      : False 
    PendFileRename : False 
    PendFileRenVal :  
    RebootPending  : True 
   
    This example will query the local machine for pending reboot information. 
   
.EXAMPLE 
    PS C:\> $Servers = Get-Content C:\Servers.txt 
    PS C:\> Get-PendingReboot -Computer $Servers | Export-Csv C:\PendingRebootReport.csv -NoTypeInformation 
   
    This example will create a report that contains pending reboot information. 
 
.LINK 
    Component-Based Servicing: 
    http://technet.microsoft.com/en-us/library/cc756291(v=WS.10).aspx 
   
    PendingFileRename/Auto Update: 
    http://support.microsoft.com/kb/2723674 
    http://technet.microsoft.com/en-us/library/cc960241.aspx 
    http://blogs.msdn.com/b/hansr/archive/2006/02/17/patchreboot.aspx 
 
    SCCM 2012/CCM_ClientSDK: 
    http://msdn.microsoft.com/en-us/library/jj902723.aspx 
 
.NOTES 
    Author:  Brian Wilhite 
    Email:   bwilhite1@carolina.rr.com 
    Date:    08/29/2012 
    PSVer:   2.0/3.0 
    Updated: 05/30/2013 
    UpdNote: Added CCMClient property - Used with SCCM 2012 Clients only 
             Added ValueFromPipelineByPropertyName=$true to the ComputerName Parameter 
             Removed $Data variable from the PSObject - it is not needed 
             Bug with the way CCMClientSDK returned null value if it was false 
             Removed unneeded variables 
             Added PendFileRenVal - Contents of the PendingFileRenameOperations Reg Entry 
#> 
 
[CmdletBinding()] 
param( 
  [Parameter(Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] 
  [Alias("CN","Computer")] 
  [String[]]$ComputerName="$env:COMPUTERNAME", 
  [String]$ErrorLog 
  ) 
 
Begin 
  { 
    # Adjusting ErrorActionPreference to stop on all errors, since using [Microsoft.Win32.RegistryKey] 
        # does not have a native ErrorAction Parameter, this may need to be changed if used within another 
        # function. 
    $TempErrAct = $ErrorActionPreference 
    $ErrorActionPreference = "Stop" 
  }#End Begin Script Block 
Process 
  { 
    Foreach ($Computer in $ComputerName) 
      { 
        Try 
          { 
            # Setting pending values to false to cut down on the number of else statements 
            $PendFileRename,$Pending,$SCCM = $false,$false,$false 
                         
                        # Setting CBSRebootPend to null since not all versions of Windows has this value 
                        $CBSRebootPend = $null 
             
            # Querying WMI for build version 
            $WMI_OS = Get-WmiObject -Class Win32_OperatingSystem -Property BuildNumber, CSName -ComputerName $Computer 
 
            # Making registry connection to the local/remote computer 
            $RegCon = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"LocalMachine",$Computer) 
             
            # If Vista/2008 & Above query the CBS Reg Key 
            If ($WMI_OS.BuildNumber -ge 6001) 
              { 
                $RegSubKeysCBS = $RegCon.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\").GetSubKeyNames() 
                $CBSRebootPend = $RegSubKeysCBS -contains "RebootPending" 
                   
              }#End If ($WMI_OS.BuildNumber -ge 6001) 
               
            # Query WUAU from the registry 
            $RegWUAU = $RegCon.OpenSubKey("SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\") 
            $RegWUAURebootReq = $RegWUAU.GetSubKeyNames() 
            $WUAURebootReq = $RegWUAURebootReq -contains "RebootRequired" 
             
            # Query PendingFileRenameOperations from the registry 
            $RegSubKeySM = $RegCon.OpenSubKey("SYSTEM\CurrentControlSet\Control\Session Manager\") 
            $RegValuePFRO = $RegSubKeySM.GetValue("PendingFileRenameOperations",$null) 
             
            # Closing registry connection 
            $RegCon.Close() 
             
            # If PendingFileRenameOperations has a value set $RegValuePFRO variable to $true 
            If ($RegValuePFRO) 
              { 
                $PendFileRename = $true 
 
              }#End If ($RegValuePFRO) 
 
            # Determine SCCM 2012 Client Reboot Pending Status 
            # To avoid nested 'if' statements and unneeded WMI calls to determine if the CCM_ClientUtilities class exist, setting EA = 0 
            $CCMClientSDK = $null 
                        $CCMSplat = @{ 
                            NameSpace='ROOT\ccm\ClientSDK' 
                            Class='CCM_ClientUtilities' 
                            Name='DetermineIfRebootPending' 
                            ComputerName=$Computer 
                            ErrorAction='SilentlyContinue' 
                            } 
                        $CCMClientSDK = Invoke-WmiMethod @CCMSplat 
            If ($CCMClientSDK) 
                            { 
                                If ($CCMClientSDK.ReturnValue -ne 0) 
                      { 
                        Write-Warning "Error: DetermineIfRebootPending returned error code $($CCMClientSDK.ReturnValue)" 
                             
                      }#End If ($CCMClientSDK -and $CCMClientSDK.ReturnValue -ne 0) 
 
                    If ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending) 
                      { 
                        $SCCM = $true 
 
                      }#End If ($CCMClientSDK.IsHardRebootPending -or $CCMClientSDK.RebootPending) 
 
                            }#End If ($CCMClientSDK) 
                        Else 
                            { 
                                $SCCM = $null 
 
                            }                         
                         
                        # If any of the variables are true, set $Pending variable to $true 
            If ($CBSRebootPend -or $WUAURebootReq -or $SCCM -or $PendFileRename) 
              { 
                $Pending = $true 
 
              }#End If ($CBS -or $WUAU -or $PendFileRename) 
               
            # Creating Custom PSObject and Select-Object Splat 
                        $SelectSplat = @{ 
                            Property=('Computer','CBServicing','WindowsUpdate','CCMClientSDK','PendFileRename','PendFileRenVal','RebootPending') 
                            } 
            New-Object -TypeName PSObject -Property @{ 
                Computer=$WMI_OS.CSName 
                CBServicing=$CBSRebootPend 
                WindowsUpdate=$WUAURebootReq 
                CCMClientSDK=$SCCM 
                PendFileRename=$PendFileRename 
                                PendFileRenVal=$RegValuePFRO 
                RebootPending=$Pending 
                } | Select-Object @SelectSplat 
 
          }#End Try 
 
        Catch 
          { 
            Write-Warning "$Computer`: $_" 
             
            # If $ErrorLog, log the file to a user specified location/path 
            If ($ErrorLog) 
              { 
                Out-File -InputObject "$Computer`,$_" -FilePath $ErrorLog -Append 
 
              }#End If ($ErrorLog) 
               
          }#End Catch 
           
      }#End Foreach ($Computer in $ComputerName) 
       
  }#End Process 
   
End 
  { 
    # Resetting ErrorActionPref 
    $ErrorActionPreference = $TempErrAct 
  }
  }
Using that function I'll do something like:
$Reboot = get-pendingreboot | % {$_.RebootPending}
If ($Reboot -eq $True) {
reboot however you feel like here.
}

New Post: Automatically elevate "Deploy-Application.EXE"?

$
0
0
Hi!

In a manual-use case (double-click Deploy-Application.EXE to start the install), the EXE file typically bombs out with an error that it's not running with administrator permissions. Right-clicking the EXE and selecting Run as Administrator works as expected.

Instead of generating a terminating error, would it be possible to have the program request elevation?

I won't claim to be an expert on Wise scripting, but based on a little bit of research, it may be doable by changing line 46 from
Requested Execution Level=asInvoker
to
Requested Execution Level=requireAdministrator
Of course, this isn't a game-breaking bug or anything, but it would be a nice convenience.

Thanks for all the hard work on this toolkit! It makes my life worlds easier.

Commented Unassigned: User not properly detected when using RDP [84]

$
0
0
When starting an update (we use ps app deploy for creating custom patches - on wsus) process while being logged on to the machine via Remote Desktop the user is not properly recocnized. This becomes an issue when applications are supposed to be closed because the window that allows to close the application is invisible to the user.
We might have a bit of a strange usage since the packages are run by the windows update agent (wua) with system priviliges and we use ServiceUi to punch it into the user session (the complete powershell script). This has been working quite well but today i noticed the issue while testing an update on an rdp connection.

[17-09-2014 14:37:08] [Initialization] No User is logged on
[17-09-2014 14:37:09] [Initialization] Session 0 not detected.
[17-09-2014 14:37:09] [Initialization] Installation is running in [Interactive] mode.

When logging on the same computer without RDP the message window with the notification to close a certain application appears and the update process continues.

[17-09-2014 14:44:16] [Initialization] The following users are logged on to the system: domain\user
[17-09-2014 14:44:16] [Initialization] Session 0 not detected.
[17-09-2014 14:44:16] [Initialization] Installation is running in [Interactive] mode.

A while ago i wrote an script to detect logged on users and noticed that quering wmi will not return users that are logged on via rdp, maybe this is the same issue
Comments: I would not consider this a bug but actual design. Detecting RDP users for the purposes of displaying a GUI to them is a task in futility. Say there is more than one user logged in via RDP. You can only display the GUI to one of the users and ask them to make a decision. How do you decide which user to choose for this action? There is no good generalized way to make this decision. The best we can do is to ignore RDP users and only display the GUI to users that are physically logged into the machine. If there is more than one users logged into the physical machine, then it is possible to discover which users currently has physical control of the mouse/keyboard/monitor and display the GUI to them. The WMI class for querying logged in users does not display RDP users to avoid the complexities that they bring...although there are other ways of getting this information from WMI.

Created Unassigned: ERROR: Value for '/TR' option cannot be more than 261 character(s) [85]

$
0
0
When attempting to block applications from launching during deployment, the toolkit creates a task using schtasks.exe.
However since it uses the full app string for the installtitle and installname (vendor+appname+version+lang+revision) it often exceeds the 261 character limit for schtasks.exe

Maybe use a truncated or shorter string for the task creation?

New Post: Specified cast is not valid. (at

$
0
0
I have a few random systems that throw the following error for an application install script. One win 7 and one win 8 all other systems seem to install fine.

Specified cast is not valid. (at<scriptBlock>.
c:....AppDeployToolkitMain.ps1:
line 1009
at Get-InstalledApplication

at Remove-MSIApplications,
c:....AppDeployToolkitMain.ps1:
line 1235

Any help or suggestions would be appreciated

New Post: Automatically elevate "Deploy-Application.EXE"?

$
0
0
Hi,

Actually the original WiseCode was as you described but it caused issues on standard user accounts, I can't recall exactly what the issue was but we decided to sacrifice the convenience in favour of resolving the issue.

Seán

New Post: Test-Powerpoint

$
0
0
I know this is an old thread, but I've figured out a way to discover when PowerPoint is actually in fullscreen presentation mode.
$FullScreenWindowSource = @'
        using System;
        using System.Text;
        using System.Runtime.InteropServices;

        namespace ScreenDetection
        {
            [StructLayout(LayoutKind.Sequential)]
            public struct RECT
            {
                public int Left;
                public int Top;
                public int Right;
                public int Bottom;
            }
            
            public class FullScreen
            {
                [DllImport("user32.dll")]
                private static extern IntPtr GetForegroundWindow();
                
                [DllImport("user32.dll")]
                private static extern IntPtr GetDesktopWindow();
                
                [DllImport("user32.dll")]
                private static extern IntPtr GetShellWindow();
                
                [DllImport("user32.dll", SetLastError = true)]
                private static extern int GetWindowRect(IntPtr hWnd, out RECT rc);

                [DllImport("user32.dll")]
                static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
                
                private static IntPtr desktopHandle;
                private static IntPtr shellHandle;
                
                public static bool IsFullScreenWindow(string fullScreenWindowTitle)
                {
                    desktopHandle = GetDesktopWindow();
                    shellHandle   = GetShellWindow();
                    
                    bool runningFullScreen = false;
                    RECT appBounds;
                    System.Drawing.Rectangle screenBounds;
                    const int nChars = 256;
                    StringBuilder Buff = new StringBuilder(nChars);
                    string mainWindowTitle = "";
                    IntPtr hWnd;
                    hWnd = GetForegroundWindow();
                    
                    if (hWnd != null && !hWnd.Equals(IntPtr.Zero))
                    {
                        if (!(hWnd.Equals(desktopHandle) || hWnd.Equals(shellHandle)))
                        {
                            if (GetWindowText(hWnd, Buff, nChars) > 0)
                            {
                                mainWindowTitle = Buff.ToString();
                                //Console.WriteLine(mainWindowTitle)
                            }
                            
                            // If the main window title contains the text being searched for, then check to see if the window is in fullscreen mode.
                            if ((!string.IsNullOrEmpty(fullScreenWindowTitle)) && mainWindowTitle.Contains(fullScreenWindowTitle))
                            {
                                GetWindowRect(hWnd, out appBounds);
                                screenBounds = System.Windows.Forms.Screen.FromHandle(hWnd).Bounds;
                                if ((appBounds.Bottom - appBounds.Top) == screenBounds.Height && (appBounds.Right - appBounds.Left) == screenBounds.Width)
                                {
                                    runningFullScreen = true;
                                }
                            }
                        }
                    }
                    
                    return runningFullScreen;
                }
            }
        }
'@
        
        If (-not ([System.Management.Automation.PSTypeName]'ScreenDetection.FullScreen').Type)
        {
            $ReferencedAssemblies = ('System.Drawing','System.Windows.Forms')
            Add-Type -TypeDefinition $FullScreenWindowSource -ReferencedAssemblies $ReferencedAssemblies -Language CSharp
        }
        
        [boolean]$IsPowerPointFullScreen = [ScreenDetection.FullScreen]::IsFullScreenWindow('PowerPoint Slide Show')

New Post: Test-Powerpoint

$
0
0
Sintaxasn, it is never too late for great ideas :) Does your code work when executed within the system context?

New Post: Test-Powerpoint

$
0
0
Yes, this should work in the system context.

New Post: Regarding the SCCM limitation with Applications and "allow user to interact with program installation"

$
0
0
OK, so I think I have found the thread I am looking for but after reading the entire thing 1) my brain hurts a bit ;) and 2) still have no idea if anything has been resolved with this. I love this tool and am working hard to get our cm12 app creation team to use it but here is how we have to use it.

We use the application model with only a very few exceptions, drivers usually.
Need to deploy apps multiple ways (some apps get used in all scenarios at the same time):
  • All users collection
  • Specific computer collections
  • OSD
I do not want to maintain 2 apps, one for users and one for system/OSD deploys as that would be a HUGE mess. We have 11 different versions of office alone due to all the languages we need.

I found this most wonderful tool right when it was on the cusp of version 3.1.5 So I am relatively new to it but have spent a lot of time reading on it, working with it and testing apps galore. I now am on v3.2.0 as it seems to have some other fixes in place and one I thought was to address this very situation. I have 1 app that will work as needed, deployed to a computer collection and still allow user interaction. None of the other items I test are working that same way, ugh. Later today I will be confirming that my deploy-application.ps1 files are correct as taken from the download source files on this site. I must be missing something. Do I maybe need to enable the Run installation and uninstall as 32-bit process on 64-bit clients option?

Now lets complicate this further ;) (we are IT its what we do).

I want to have the 'core' files centrally located on all the computers in my site, makes long term management easier so say I want it like this C:\windows\Brunswick\AppDeployToolKit and in it will be every file needed to run the deploy-application.ps1 script. So far works GREAT, unless i try to use deploy-application.exe :( It says it cant locate the files. Is there a way to pas a path to the exe so it can locate the source code?

thanks in advance for everyone's hard work on this most excellent adventure (I mean tool)

New Post: Unable to find "AppDeploymentkit" Folder

$
0
0
@ener2014 interesting, and the exe still works as needed?


here is how I did it....

$scriptDirectory = Split-Path -Parent "$env:SYSTEMROOT\Brunswick\AppDeployToolkit"

."$scriptDirectory\AppDeployToolkit\AppDeployToolkitMain.ps1"

doing so though forces you to abandon the deploy-application.exe and then run your installs using the script directly. aka powershell.exe .\deploy-application.ps1

New Post: Test-VPNConnection Function: Need help testing to see if it works reliably in other environments

$
0
0
Hey community,

I have developed a function to detect if the system is currently connected via VPN. I want to make sure that it is able to reliably detect VPN connections in other environments as well. Could you please help out by executing this code in your environment and letting me know if it successfully detected the VPN connection? Also, run the code when not connected to VPN so as to make sure that it does not give any false positives. If the function is not able to detect the VPN on your system, can you see which piece of data is able to reliably find the VPN connection and share that?

Thanks!
Function Test-VPNConnection
{
<#
.SYNOPSIS
    Check to see if there is an active VPN connection.
    
.DESCRIPTION
    Check to see if there is an active VPN connection by using the Win32_NetworkAdapter and the 
    Win32_NetworkAdapterConfiguration WMI classes.
    
.PARAMETER LikeAdapterDescription
    Matches on the network adapter description field using wild card matching.
    
.PARAMETER NotMatchAdapterDescription
    Excludes on the network adapter description field using regex matching.
    
.PARAMETER LikeAdapterDNSDomain
    Matches on the network adapter DNS Domain field using wild card matching.
    
.PARAMETER LikeAdapterDHCPServer
    Matches on the network adapter DHCP Server field using wild card matching.
    
.PARAMETER LikeAdapterDefaultGateway
    Matches on the network adapter Default Gateway field using wild card matching. 
    
.PARAMETER DisplayNetworkAdapterTable
    Logs the full list of network adapters and also the filterd list of possible VPN connection
     network adapters.
    
.EXAMPLE
    Test-VPNConnection
    
.NOTES
.LINK
    
#>
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$false)]
        [ValidateNotNullorEmpty()]
        [string[]]$LikeAdapterDescription = ('*vpn*','*juniper*','*check point*'),
        
        [Parameter(Mandatory=$false)]
        [ValidateNotNullorEmpty()]
        [string[]]$NotMatchAdapterDescription = ('^WAN Miniport','^Microsoft','^VMware Virtual','VirtualBox','^Bluetooth Device','^RAS Async Adapter','USB'),
        
        [Parameter(Mandatory=$false)]
        [ValidateNotNullorEmpty()]
        [string[]]$LikeAdapterDNSDomain = ('*.com'),
        
        [Parameter(Mandatory=$false)]
        [ValidateNotNullorEmpty()]
        [string[]]$LikeAdapterDHCPServer,
        
        [Parameter(Mandatory=$false)]
        [ValidateNotNullorEmpty()]
        [string[]]$LikeAdapterDefaultGateway,
        
        [Parameter(Mandatory=$false)]
        [switch]$DisplayNetworkAdapterTable = $false
    )
    
    Begin
    {
        ## Get the name of this function
        [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
        
        #Write-FunctionHeader -CmdletName ${CmdletName} -CmdletBoundParameters $PSBoundParameters
        
        [scriptblock]$NotMatchDescription = {
                [CmdletBinding()]
                Param
                (
                    [Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
                    $sbInputObject,
                    
                    [Parameter(Mandatory=$true,Position=1)]
                    $sbNotMatchAdapterDescription
                )
                $SendToPipeline = $false
                ForEach ($sbNotMatchDesc in $sbNotMatchAdapterDescription)
                {
                    If (-not ($sbInputObject.Description -imatch $sbNotMatchDesc))
                    {
                        $SendToPipeline = $true
                    }
                    Else
                    {
                        $SendToPipeline = $false
                        Break
                    }
                }
                Write-Output $SendToPipeline
            }
    }
    Process
    {
        Try
        {
            [psobject[]]$AllNetworkAdapter           = Get-WmiObject Win32_NetworkAdapter -ErrorAction 'Stop' |
                                                       Select-Object -Property DeviceID, PNPDeviceID, Manufacturer
            
            [psobject[]]$AllNetworkAdapterConfigTemp = Get-WmiObject Win32_NetworkAdapterConfiguration -ErrorAction 'Stop' |
                                                       Select-Object -Property @{L='DeviceID'; E={$_.Index}}, DNSDomain, DefaultIPGateway, DHCPServer, IPEnabled, PhysicalAdapter, Manufacturer, Description
            $AllNetworkAdapterConfig = $null
            ForEach ($AdapterConfig in $AllNetworkAdapterConfigTemp)
            {
                ForEach ($Adapter in $AllNetworkAdapter)
                {
                    If ($AdapterConfig.DeviceID -eq $Adapter.DeviceID)
                    {
                        ## Note: We create our own custom PhysicalAdapter property b/c the one in the
                        ##       Win32_NetworkAdapter class is not accurate.
                        $AdapterConfig.PhysicalAdapter        = [boolean]($Adapter.PNPDeviceID  -imatch '^PCI\\')
                        $AdapterConfig.Manufacturer           = $Adapter.Manufacturer
                        [psobject[]]$AllNetworkAdapterConfig += $AdapterConfig
                    }
                }
            }
            
            ## This table contains the major markers that might help user create the criteria for detecting VPN connections.
            [string]$AllNetworkAdapterConfigTable   = $AllNetworkAdapterConfig |
                                                      Format-Table DNSDomain, DefaultIPGateway, DHCPServer, IPEnabled, PhysicalAdapter, Manufacturer, Description -AutoSize -Wrap | Out-String
            
            ## Sanitize list of Network Adapters by removing:
            ##  a) adapters which we know are not VPN connections
            ##  b) adapters which are not connected (IP Enabled)
            [psobject[]]$NetworkAdapterConfig       = $AllNetworkAdapterConfig |
                                                      Where-Object  { -not ($_.PhysicalAdapter) } |
                                                      Where-Object  {
                                                                        &$NotMatchDescription -sbInputObject $_ -sbNotMatchAdapterDescription $NotMatchAdapterDescription
                                                                    } |
                                                      Where-Object  { $_.IpEnabled }
            [string]$NetworkAdapterConfigTable      = $NetworkAdapterConfig |
                                                      Format-Table DNSDomain, DefaultIPGateway, DHCPServer, IPEnabled, PhysicalAdapter, Manufacturer, Description -AutoSize -Wrap | Out-String
            
            ## Display Network Adapter Tables
            If ($DisplayNetworkAdapterTable)
            {
                Write-Host "All network adapters: `n$AllNetworkAdapterConfigTable" -ForegroundColor 'Magenta'
                Write-Host "Filtered to possible VPN network adapters: `n$NetworkAdapterConfigTable" -ForegroundColor 'Yellow'
            }
            
            ## Precedence Order 1:
            ##  Detect VPN connection based on name of manufacturer in network adapter description field. Search is case insensitive.
            If ($LikeAdapterDescription)
            {
                ForEach ($LikeDescription in $LikeAdapterDescription)
                {
                    If ([boolean]($NetworkAdapterConfig | Where-Object {($_ | Select-Object -ExpandProperty Description) -ilike $LikeDescription}))
                    {
                        Return $true
                    }
                }
            }
            
            ## Precedence Order 2:
            ##  Detect VPN based on DNS domain (e.g.: contoso.com).
            If ($LikeAdapterDNSDomain)
            {
                ForEach ($LikeDNSDomain in $LikeAdapterDNSDomain)
                {
                    If ([boolean]($NetworkAdapterConfig | Where-Object {($_ | Select-Object -ExpandProperty DNSDomain) -ilike $LikeDNSDomain}))
                    {
                        Return $true
                    }
                }
            }
            
            ## Precedence Order 3:
            ##  Detect VPN connection based on the DHCP Server of the network adapter
            If ($LikeAdapterDHCPServer)
            {
                ForEach ($LikeDHCPServer in $LikeAdapterDHCPServer)
                {
                    If ([boolean]($NetworkAdapterConfig | Where-Object {($_ | Select-Object -ExpandProperty DHCPServer) -ilike $LikeDHCPServer}))
                    {
                        Return $true
                    }
                }
            }
            
            ## Precedence Order 4:
            ##  Detect VPN connection based on the default gateway for the network adapter
            If ($LikeAdapterDefaultGateway)
            {
                ForEach ($LIkeDefaultGateway in $LikeAdapterDefaultGateway)
                {
                    If ([boolean]($NetworkAdapterConfig | Where-Object {($_ | Select-Object -ExpandProperty DefaultIPGateway) -ilike $LIkeDefaultGateway}))
                    {
                        Return $true
                    }
                }
            }
            Return $false
        }
        Catch
        {
            #Write-Log " `n$(Resolve-Error)"
            Return $false
        }
    }
    End
    {
         #Write-FunctionFooter -CmdletName ${CmdletName}
    }
}

If (Test-VPNConnection -DisplayNetworkAdapterTable)
{
    Write-Host 'VPN Connection Detected' -ForegroundColor 'Green'
}
Else
{
    Write-Host 'VPN Connection Not Detected' -ForegroundColor 'Green'
}

New Post: ConvertTo-LargestByteSize

$
0
0
Function ConvertTo-LargestByteSize
{
<#
.SYSNOPSIS
    Converts a size in bytes to its upper most value.
    
.DESCRIPTION
    Converts a size in bytes to its upper most value.
    
.PARAMETER Size
    The size in bytes to convert
    
.EXAMPLE
    ConvertTo-LargestByteSize -Size 568956
    555 KB
    
    Description
    -----------
    Converts the byte value 568956 to upper most value of 555 KB
    
.EXAMPLE
    Get-ChildItem  |
    Where-Object {-not ($_.PSIsContainer)} |
    Select-Object -First 5 |
    Select-Object -Property Name, @{L='Size';E={$_ | ConvertTo-LargestByteSize}}
    
    Name                                                           Size
    ----                                                           ----
    Data1.cap                                                      14.4 MB
    Data2.cap                                                      12.5 MB
    Image.iso                                                      5.72 GB
    Index.txt                                                      23.9 KB
    SomeSite.lnk                                                   1.52 KB
    SomeFile.ini                                                   152 bytes
    
    Description
    -----------
    Used with Get-ChildItem and custom formatting with Select-Object to list the uppermost size.
    
.NOTES
.LINK
#>
    [CmdletBinding()]
    Param
    (
        [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
        [long]$Size
    )
    Begin
    {
        $ConvertToLargestByteSizeSource =  @'
        using System;
        using System.Text;
        using System.Runtime.InteropServices;
        
        namespace Convert
        {
            public class Byte
            {
                [DllImport("shlwapi.dll", CharSet = CharSet.Auto)]
                public static extern long StrFormatByteSize(long fileSize, StringBuilder buffer, int bufferSize);
                
                public static string ConvertToLargestByteSize(long size)
                {
                    const int nChars = 256;
                    StringBuilder Buff = new StringBuilder(nChars);
                    
                    StrFormatByteSize(size, Buff, Buff.Capacity);
                    return Buff.ToString();
                }
            }
        }
'@
        If (-not ([System.Management.Automation.PSTypeName]'Convert.Byte').Type)
        {
            Add-Type -TypeDefinition $ConvertToLargestByteSizeSource -Language CSharp
        }
    }
    Process
    {
        Write-Log "Converting [$Size bytes] to upper most size"
        [string]$LargestByteSize = [Convert.Byte]::ConvertToLargestByteSize($Size)
        Write-Output $LargestByteSize
    }
}

New Post: Block-AppExecution function....

$
0
0
Hi all

For better user experience, I display the popup "Show-InstallationWelcome" only if there is a process launched.....
If the process not launch, toolkit blocks the process until the install be finished....

I known it's not recommended but this is the only way I found to reduce popup to users !

Here is the code :
#*===============================================
#* PRE-INSTALLATION
If ($deploymentType -ne "uninstall") { $installPhase = "Pre-Installation"
#*===============================================

    # =========================================================
    # If proccess open = Show-InstallationWelcome
    # If proccess NOT open = Block-AppExecution 
    # =========================================================

    if (Get-Process -Name ProcessName1,ProcessName2,ProcessName3 -ErrorAction SilentlyContinue)
        {
        Show-InstallationWelcome -CloseApps "ProcessName1,ProcessName2,ProcessName3"  -BlockExecution -AllowDefer -DeferTimes "20" -CheckDiskSpace -PersistPrompt
        }

    Block-AppExecution -ProcessName ProcessName1,ProcessName2,ProcessName3


    # =========================================================
    # Install
    # =========================================================

Whatever


    # =========================================================
    # Unblock 
    # =========================================================
    UnBlock-AppExecution


#*===============================================
#* POST-INSTALLATION
$installPhase = "Post-Installation"
#*===============================================
it works great only if the command line that blocks applications does not exceed 261 characters :

[Pre-Installation] Executing [C:\WINDOWS\System32\schtasks.exe /Create /TN Manufacturer001_Application01_10.0_EN__BlockedApps /RU System /SC ONSTART /TR "powershell.exe -ExecutionPolicy Bypass -NoProfile -WindowStyle Hidden -File 'C:\Users\Public\PSAppDeployToolkit\AppDeployToolkitMain.ps1' -CleanupBlockedApps -InstallTitle 'Manufacturer001 Application01 10.0' -InstallName 'Manufacturer001_Application01_10.0_EN_'"]

[Pre-Installation] Standard error output from the process []: Error: The value for the option '/ TR' can not contain more than 261 characters.

Do you think it's possible :
  • Block applications if the proccess are not launched ?
or how to have a evolution of this function ?

Thanks a lot
Viewing all 2341 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>