Let us know how it goes.
↧
New Post: New to the PDT
↧
New Post: Create new folder using New-Item
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:
Then I tried to modify the one in the post to create the folder:
thanks
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
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:
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]
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.
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?
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.
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
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?
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"?
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
Thanks for all the hard work on this toolkit! It makes my life worlds easier.
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
toRequested 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]
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.
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]
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?
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
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
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"?
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
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
Sintaxasn, it is never too late for great ideas :) Does your code work when executed within the system context?
↧
New Post: Test-Powerpoint
Yes, this should work in the system context.
↧
New Post: Regarding the SCCM limitation with Applications and "allow user to interact with program installation"
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):
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)
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 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
@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
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
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!
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
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....
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] 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 :
Thanks a lot
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 ?
Thanks a lot
↧