New-WebApplication fails using network path in physicalpath parameter in powershell - powershell

We are trying to create list of applications in a particular site,
For this we have a csv which contains required information for site creation. Below is the format:
Below is the script which we are using to create application in IIS:
foreach($app in $apps){
$appname = $app.path.TrimStart("/")
New-WebApplication -Name $appname -Site $app.Site -PhysicalPath $app.PhysicalPath -ApplicationPool $app.applicationPool -Verbose
}
Problem is application whose code is stored on some network path like \\network\Webapps\appname are giving below error:
New-WebApplication : A parameter cannot be found that matches parameter name 'physicalPath'.
whereas application folder located on same server are being created without any issue,
Have also done test-path \\network\webapps\appname it results in true
What is the issue and how to rectify it?

Issue got resolved, I didn't got what was the exact reason behind that, Have updated my script, basically have assigned values to specific variable than was able to create application.
Updated Script
foreach($app in $apps){
$appname = $app.path.TrimStart("/")
$appSite = $app.Site
$appPath = $app.PhysicalPath
$appPool = $app.applicationPool
New-WebApplication -Name $appname -Site $appSite -PhysicalPath $appPath -ApplicationPool $appPool -Verbose
}
Thanks

First of all, you have to make sure that powershell has permission to access the server corresponding to the network path when creating the site.
When using powershell to create a site, if the physical path of the site is a file in the local disk, you can use New-WebApplication, if it is a UNC path, you should use New-Item.
Under normal circumstances, the UNC path will not be used as the physical path of the main site, but will be added as a virtual directory. Because the domain name of the main site points to the local machine and the UNC points to the remote IP address, the two will conflict because a server error occurred when I created the site through IIS Manager.
$siteName = 'Default Web Site'
$virtualDirectoryName = 'Test'
$physicalPath = '\\UNC-path'
## Init
$virtualDirectoryPath = "IIS:\Sites\$siteName\$virtualDirectoryName"
## Create Virtual Directory where physicalpath is an UNC-path (New-WebVirtualDirectory
wont do)
New-Item $virtualDirectoryPath -type VirtualDirectory -physicalPath $physicalPath

Any chance it's this? That error sounds like it's an issue with the cmdlet and not the data you're feeding it.
https://social.msdn.microsoft.com/Forums/en-US/3e0cb076-6ad4-4b03-bb59-c912174266b0/container-with-iis-cant-create-application-using-powershell-physicalpath-parameter-not-found?forum=windowscontainers
specifically:
You need to import the WebAdministration module. If you're in the container through docker exec simply use:
Import-Module WebAdministration

Related

Copy a file to a remote computer

I have made two instances on sky-high; cl1 and srv1. I am trying to copy a folder from cl1 to srv1. I can use the command
Enter-PSSession -Credential $cred IP_ADD_SRV1
from cl1 to get into srv1. I have been looking at the help site for copy-item and found this command called Copy a file to a remote computer. Is this right? The command is
$Session = New-PSSession -ComputerName "Server01" -Credential "Contoso\User01"
Copy-Item "D:\Folder001\test.log" -Destination "C:\Folder001_Copy\" -ToSession $Session
My questions are:
Is the ComputerName just the name I called them on my Microsoft Remote Desktop?
And what do I put as the credential?
My problem is that the path for the two folders I want to copy are almost the same. Someone told me I need to use the UNC path. Do I need to use this
both at the copy-item and destination? I am new to this, but does
this look right for the UNC path: \\cl1\C$\Users\Admin\Test. ?
You can copy a file or folder from a pc to a remote machine in several ways.
A 'Normal' copy (not using a Session object)
if the pc you are logged into is called cl1 and the file is on that computer (source), you need to specify the Destination in UNC format:
Copy-Item -Path 'C:\SourceFolder\TheFileToCopy.txt' -Destination '\\srv1\c$\DestinationFolder'
If however the file is on the remote machine and you need to copy that TO the machine you're logged into, then the Source should be in UNC format:
Copy-Item -Path '\\srv1\c$\TheFileToCopy.txt' -Destination 'C:\DestinationFolder'
Using the Session object
if the pc you are logged into is called cl1 and the file is on that computer (source) and you have established a session using $session = New-PSSession –ComputerName srv1 to the remote machine, then you need to specify both the Path and Destination parameters as LOCAL paths:
Copy-Item -Path 'C:\SourceFolder\TheFileToCopy.txt' -Destination 'C:\DestinationFolder' -ToSession $session
A Credential object contains user name and (encrypted) password to use to authenticate to the remote machine. Use the Get-Credential cmdlet for that
It seems you want to copy a directory from a source on computer Cl1 to a path on the remote server srv1.
From your comments, I see that the source is C:\Users\Admin\Test (that is the LOCAL path of the computer you are logged in to, i.e. Cl1) and that the destination would be C:\Users\Admin\Backup on the REMOTE machine.
That is why you need to use the UNC format for the destination path, C:\Users\Admin\Backup --> \\srv1\C$\Users\Admin\Backup.
Using the servers name needs DNS to be set up properly, so you can also use the IP address of that server instead of its name. Suppose that the server has IP 10.212.141.129, the UNC path for the destination would then become \\10.212.141.129\C$\Users\Admin\Backup.
However.. You are targetting the so-called Administrative Share (C$), and for that you need to have permissions. Also you are targetting a user folder for user Admin (which is user Admin on the remote machine, and that is not the same one as the Administrator on your computer.
Therefore, it is quite possible you do not have access permissions on the target folder.
You can give yourself permissions (if you know the correct credentials of course) by adding parameter -Credential $cred to the Copy-Item cmdlet. Such a credentials object is easily obtained by using
$cred = Get-Credential -Message "Please enter Domain Admin credentials"
For Copy-Item to be able to copy something to somewhere, you must make sure the destination path exists.
Try to navigate in File Explorer to that remote path using the same UNC naming convention.
If for instance the path \\srv1\C$\Users\Admin exists, but there is no folder Backup, (and you have permissions to do so), create that folder, either from within Explorer, or in PowerShell:
if (-not (Test-Path -LiteralPath '\\srv1\C$\Users\Admin\Backup' -PathType Container)) {
$null = New-Item -Path '\\srv1\C$\Users\Admin\Backup' -ItemType Directory
}
Next, you should be able to copy all files and subfolders from the source directory to that destination using
Copy-Item -Path 'C:\Users\Admin\Test' -Destination '\\srv1\C$\Users\Admin\Backup' -Recurse # -Credential $cred # can go here
# local source on cl1 ^^^^ ^^^^ to remote destination on srv1
Of course, you can also use the Session method I've described earlier., where in that case you should use local pathnames (C:\whatever) and don't need UNC paths, because the $session object takes care of that for you.
It could be that on the destination server, there is a share set-up for you that resides somewhere else. For instance a folder X:\Students\Course1\Output and that path has been shared as StudentMaterial$.
If this might be the case (ask your teacher) you can set the destination as \\srv1\StudentMaterial$ and you do not need to go all the way via the Administrative Share.
Hope this explains some more

Connecting Exchange Online Fails when passing proxy and running in System PowerShell - TokenProvider Returns Object Reference Error

I was connecting Exchange Online using a PowerShell window that is opened with system access. I used PSExec on an elevated Command Prompt to open the System access PowerShell. Below is the command.
PSExec -i -s PowerShell
On the PowerShell, I imported the latest Exchange Online Management PowerShell module version 2.0.3. I use the app-based authentication described here: https://learn.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps#setup-app-only-authentication.
There is one more website that shows how to connect with app-based authentication: https://o365reports.com/2020/07/04/modern-auth-and-unattended-scripts-in-exchange-online-powershell-v2.
Below are the commands used to connect to Exchange Online.
Import-Module .\ExchangeOnlineManagement
$sessopt = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck -ProxyAccessType IEConfig
$certkey = ConvertTo-SecureString "<EnterCertificateKeyHere>" -AsPlainText -Force
Connect-ExchangeOnline -CertificateFilePath "pfx Certificate Path" -AppId <EnterAppIdHere> -Organization "domain.onmicrosoft.com" -CertificatePassword $certkey -PSSessionOption $sessopt -verbose
When running the above, it returns Object Reference error. I got excited and went on to find what the error is by decompiling the DLL files and found that inside the 'ExoPowershellGalleryModule.dll -> NewExoPSSession.cs' of the Exchange module, the 'GetAccessToken' function which is called around line:308 causes this error. Any idea what makes the Object reference not set to an instance of an object. System.Management.Automation.RemoteException: Object reference not set to an instance of an object. error. Was the proxy not taken from IE?
I've set the proxy settings in IE using the below Powershell command-lets in system PowerShell.
Set-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -name ProxyServer -Value "ProxyServerAddress"
Set-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -name ProxyEnable -Value 1
Any help to resolve this is appreciated.
If your using
PSExec -i -s PowerShell
Then the proxy information your entering for the user will have no effect because the local system account will have its own profile information. Also if the proxy needs authentication you also won't be presenting any Network credentials.
If you really want to run under the system account you could try using netsh to configure the proxy https://learn.microsoft.com/en-us/windows/security/threat-protection/microsoft-defender-atp/configure-proxy-internet but if you proxy need authentication this won't work.

Duplicate entry warning in Powershell script while working with IIS?

My script is whitelisting IP for a particular URL in IIS.
Set-WebConfigurationProperty -Filter /system.webserver/security/ipsecurity -Name allowUnlisted -Value $false -Location "default web site"
Add-WebConfiguration /system.webserver/security/ipsecurity -location "default web site" -Value #{ipAddress = 129.0.0.1 ;subnetmask = 255.255.255.0 ;allowed="true"} -pspath IIS:\
It works perfectly except when I remove the entry manually from IIS, and again i try to run this script it warns me "cannot add duplicate entry of type add". I cannot see the entry in IIS. Is there a way to remove that duplicate entry via powershell.
Reason behind this is that, applicationhost.config file in inetserv folder has that entry. If you add it via script, remove it via script, or you can open config file in notepad and find the entry and delete it. Save the file after.

net use * /delete /y doesn't resolve error "New-PSDrive : Multiple connections to a server ...."

This New-PSDrive command
New-PSDrive -Name Z -PSProvider FileSystem -Root \\$j\share -Credential $credentials -ErrorAction Stop
Causes the error
New-PSDrive : Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the
server or shared resource and try again
I have tried disconnecting all drives first, then creating new drive,
net use * /delete /y
New-PSDrive -Name Z -PSProvider FileSystem -Root \\$j\share -Credential $credentials -ErrorAction Stop
I get the output
You have these remote connections:
\\TSCLIENT\C
\\TSCLIENT\D
\\TSCLIENT\E
\\TSCLIENT\I
\\TSCLIENT\J
\\TSCLIENT\K
\\TSCLIENT\L
\\TSCLIENT\R
\\TSCLIENT\T
Continuing will cancel the connections.
The command completed successfully.
New-PSDrive : Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the
server or shared resource and try again
I also tried removing the Z drive first
Remove-PSDrive -name Z
New-PSDrive -Name Z -PSProvider FileSystem -Root \\$j\share -Credential $credentials -ErrorAction Stop
And get error
Remove-PSDrive : Cannot find drive. A drive with the name 'Z' does not exist.
...
New-PSDrive : Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the
server or shared resource and try again
How to fix?
UPDATE
I even rebooted the machine and changed the drive name, but I still get the same error of "New-PSDrive: Multiple connections ......"
UPDATE 2
I have also tried using IP address instead of computer name, but that doesn't work either, http://support.microsoft.com/kb/938120
I found workaround to this problem that seem to always work. You need to change the computer name, but since this will also stop working eventually just as with server name and IP, you need the option to specify arbitrary number of new computer names resolving to the same computer.
The obvious choice is hosts file. You can add any number of aliases to the IP to it. Afterwards, use the alias that isn't already blocked.
==== EDIT ===
Here is the handy function:
<# Use unique hostname for this script by altering hosts table to handle situation with multiple different scripts
using this share with different creds which leads to following Windows error:
Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed.
Disconnect all previous connections to the server or shared resource and try again
#require -RunAsAdministrator
#require -module PsHosts
https://stackoverflow.com/a/29059100/82660
#>
function Set-UncHostnameAlias($UncPath) {
$remote_hostname = $UncPath -split '\\' | ? {$_} | select -First 1
$remote_alias = (Split-Path -Leaf $MyInvocation.ScriptName) -replace '.ps1$'
$hostEntry = Get-HostEntry $remote_alias* -ea 0 | ? { $_.Comment -eq $remote_hostname } | select -First 1
if (!$hostEntry) {
$remote_alias += (Get-HostEntry $remote_alias*).Count + 1
Write-Verbose "Adding alias $remote_alias => $remote_hostname"
$remote_ip = Test-Connection -ComputerName $remote_hostname -Count 1 | % IPV4Address | % IPAddressToString
Add-HostEntry -Name $remote_alias -Address $remote_ip -Force -Comment $remote_hostname | Out-Null
} else {
$remote_alias = $hostEntry.Name
Write-Verbose "Using $remote_hostname alias: $remote_alias"
}
$UncPath.Replace("\\$remote_hostname", "\\$remote_alias")
}
Do this on the start of the script:
$PathAlias = Set-UncHostnameAlias $Path
and used aliased path afterwards with the New-PSDrive. This works always, even if some other scripts on the same system use different credentials for the same server.
I was having the same issue with local scripts and found this to be a simple solution. The Get-CimInstance returns all of the mapped network connections, then just pass that to the net use /delete /y command.
$shareDrives = Get-CimInstance -ClassName Win32_NetworkConnection
if ($shareDrives -ne $null)
{
foreach ($shareDrive in $shareDrives)
{
Write-Host "`nRemoving mapped drive $($shareDrive.LocalName)"
net use $shareDrive.LocalName /delete /y
}
}
else
{
Write-Host "`nNo mapped drives to remove!"
}
Using the FQND worked for me..
How to find out FQDN??
ping -a -n 1
Pinging [This is the FQND!!!!] [192.168.0.1] with 32 bytes of
Reply from 192.168.0.1: bytes=32 time=1ms TTL=128
You need to use the FQDN instead of the NetBios name.
My script needs to be client computer independent since other members of my team might run it. This works for me. Not sure if the "Write-Host" is needed but it also doesn't get in the way. Also, there is some sort of error that doesn't affect using the drive again if it already exists.
if (Get-PSDrive DLL_NEW_TEMP -ErrorAction SilentlyContinue){Write-Host "DLL_NEW_TEMP Drive exists"}
else{
New-PSDrive -Name DLL_NEW_TEMP -PSProvider FileSystem -Root \\WTDHSxxxL32\d$\ServerDLLDev\New_DLL_temp_location -Credential $credential
}
if (Get-PSDrive DLL_WORKING -ErrorAction SilentlyContinue){Write-Host "DLL_WORKING Drive exists"}
else{
New-PSDrive -Name DLL_WORKING -PSProvider FileSystem -Root \\WTDHSxxx32\d$\ServerDLLDev -Credential $credential
}
The below information I found on here
This error message means that you already have a connection to that UNC path, whether it's defined on your computer or not. Windows only allows you to connect to a particular UNC path with one username, regardless of the number of connections to that UNC. If you use the same username for all connections to a UNC from your computer then you shouldn't run into this error.
My issue and its solution: I was connected to the shared drive and it was open in my session with my credentials and at the same I've tried to run New-PSDrive with other credential. After closing my session with the shared drive the command worked like a pro.
If you have to use a different username to connect, then one workaround is to connect to the UNC using an IP address or other alias so that it looks like it's a different path. This is also the workaround recommended by Microsoft:

Powershell - Copying File to Remote Host and Executing Install exe using WMI

EDITED: Here is my code now. The install file does copy to the remote host. However, the WMI portion does not install the .exe file, and no errors are returned. Perhaps this is a syntax error with WMI? Is there a way to just run the installer silently with PsExec? Thanks again for all the help sorry for the confusion:
#declare params
param (
[string]$finalCountdownPath = "",
[string]$slashes = "\\",
[string]$pathOnRemoteHost = "c:\temp\",
[string]$targetJavaComputer = "",
[string]$compname = "",
[string]$tempPathTarget = "\C$\temp\"
)
# user enters target host/computer
$targetJavaComputer = Read-Host "Enter the name of the computer on which you wish to install Java:"
[string]$compname = $slashes + $targetJavaComputer
[string]$finalCountdownPath = $compname + $tempPathTarget
#[string]$tempPathTarget2 =
#[string]$finalCountdownPath2 = $compname + $
# say copy install media to remote host
echo "Copying install file and running installer silently please wait..."
# create temp dir if does not exist, if exist copy install media
# if does not exist create dir, copy dummy file, copy install media
# either case will execute install of .exe via WMII
#[string]$finalCountdownPath = $compname + $tempPathTarget;
if ((Test-Path -Path $finalCountdownPath) )
{
copy c:\hdatools\java\jre-7u60-windows-i586.exe $finalCountdownPath
([WMICLASS]"\\$targetJavaComputer\ROOT\CIMV2:win32_process").Create("cmd.exe /c c:\temp\java\jre-7u60-windows-i586.exe /s /v`" /qn")
}
else {
New-Item -Path $finalCountdownPath -type directory -Force
copy c:\hdatools\dummy.txt $finalCountdownPath
copy "c:\hdatools\java\jre-7u60-windows-i586.exe" $finalCountdownPath
([WMICLASS]"\\$targetJavaComputer\ROOT\CIMV2:win32_process").Create("cmd.exe /c c:\temp\java\jre-7u60-windows-i586.exe /s /v`" /qn")
}
I was trying to get $Job = Invoke-Command -Session $Session -Scriptblock $Script to allow me to copy files on a different server, because I needed to off load it from the server it was running from. I was using the PowerShell Copy-Item to do it. But the running PowerShell script waits until the file is done copying to return.
I want it to take as little resources as possible on the server that the powershell is running to spawn off the process on another server to copy the file. I tried to user various other schemes out there, but they didn't work or the way I needed them to work. (Seemed kind of kludgey or too complex to me.) Maybe some of them could have worked? But I found a solution that I like that works best for me, which is pretty easy. (Except for some of the back end configuration that may be needed if it is is not already setup.)
Background:
I am running a SQLServer Job which invokes Powershell to run a script which backups databases, copies backup files, and deletes older backup files, with parameters passed into it. Our server is configured to allow PowerShell to run and under the pre-setup User account with SQL Server Admin and dbo privileges in an Active Directory account to allow it to see various places on our Network as well.
But we don't want it to take the resources away from the main server. The PowerShell script that was to be run would backup the database Log file and then use the another server to asynchronously copy the file itself and not make the SQL Server Job/PowerShell wait for it. We wanted it to happen right after the backup.
Here is my new way, using WMI, using Windows Integrate Security:
$ComputerName = "kithhelpdesk"
([Wmiclass]'Win32_Process').GetMethodParameters('Create')
Invoke-WmiMethod -ComputerName RemoteServerToRunOn -Path win32_process -Name create -ArgumentList 'powershell.exe -Command "Copy-Item -Path \\YourShareSource\SQLBackup\YourDatabase_2018-08-07_11-45.log.bak -Destination \\YourShareDestination\YourDatabase_2018-08-07_11-45.log.bak"'
Here is my new way using passed in Credentials, and building arg list variable:
$Username = "YouDomain\YourDomainUser"
$Password = "P#ssw0rd27"
$ComputerName = "RemoteServerToRunOn"
$FromFile = "\\YourShareSource\SQLBackup\YourDatabase_2018-08-07_11-45.log.bak"
$ToFile = "\\YourShareDestination\SQLBackup\YourDatabase_2018-08-07_11-45.log.bak"
$ArgumentList = 'powershell.exe -Command "Copy-Item -Path ' + $FromFile + ' -Destination ' + $ToFile + '"'
$SecurePassWord = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $Username, $SecurePassWord
([Wmiclass]'Win32_Process').GetMethodParameters('Create')
Invoke-WmiMethod -ComputerName $ComputerName -Path win32_process -Name create -ArgumentList $ArgumentList -Credential $Cred
We think that this above one is the preferred one to use.
You can also run a specific powershell that will do what you want it to do (even passing in parameters to it):
Invoke-WmiMethod -ComputerName RemoteServerToRunOn -Path win32_process -Name create -ArgumentList 'powershell.exe -file "C:\PS\Test1.ps1"'
This example could be changed to pass in parameters to the Test1.ps1 PowerShell script to make it more flexible and reusable. And you may also want to pass in a Credential like we used in a previous example above.
Help configuring WMI:
I got the main gist of this working from: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/invoke-wmimethod?view=powershell-5.1
But it may have also needed WMI configuration using:
https://helpcenter.gsx.com/hc/en-us/articles/202447926-How-to-Configure-Windows-Remote-PowerShell-Access-for-Non-Privileged-User-Accounts?flash_digest=bec1f6a29327161f08e1f2db77e64856b433cb5a
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/enable-psremoting?view=powershell-5.1
Powershell New-PSSession Access Denied - Administrator Account
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/invoke-wmimethod?view=powershell-5.1 (I used to get how to call Invoke-WmiMethod).
https://learn.microsoft.com/en-us/powershell/scripting/core-powershell/console/powershell.exe-command-line-help?view=powershell-6 (I used to get syntax of command line)
I didn't use this one, but could have: How to execute a command in a remote computer?
I don't know for sure if all of the steps in the web articles above are needed, I suspect not. But I thought I was going to be using the Invoke-Command PowerShell statement to copy the files on a remote server, but left my changes from the articles above that I did intact mostly I believe.
You will need a dedicated User setup in Active Directory, and to configure the user accounts that SQL Server and SQL Server Agent are running under to give the main calling PowerShell the privileges needed to access the network and other things to, and can be used to run the PowerShell on the remote server as well. And you may need to configure SQLServer to allow SQL Server Jobs or Stored Procedures to be able to call PowerShell scripts like I did. But this is outside the scope of this post. You Google other places on the internet to show you how to do that.