I have Power Shell script for publish/update new dll's for running windows service:
Import-Module WebAdministration
function Main(
[string] $siteName = $(Throw "Value cannot be null: siteName"),
[string] $sitePath = $(Throw "Value cannot be null: sitePath"),
[string] $servicePath = $(Throw "Value cannot be null: sitePath"),
[string] $serviceName = $(Throw "Value cannot be null: sitePath"),
[string] $buildConfiguration = $(Throw "Value cannot be null: sitePath"))
{
...
$serviceBinPath = Join-Path $serviceBinPath $buildConfiguration
Write-Host "Directory of Windows Service : $($serviceBinPath )`r`n"
StopWindowsService $serviceName
RemoveFiles $servicePath
CopyFiles $serviceBinPath $servicePath
StartWindowsService $serviceName
}
function RemoveFiles(
[string] $path = $(Throw "Value cannot be null: sitePath"))
{
If (Test-Path $path)
{
Write-Host "Removing folder ($path)...`r`n"
Remove-Item -Recurse -Force "$($path)*"
Write-Host "Successfully removed website folder ($path)...`r`n"
}
}
function CopyFiles(
[string] $sourcePath = $(Throw "Value cannot be null: sitePath"),
[string] $destinationPath = $(Throw "Value cannot be null: sitePath"))
{
If ((Test-Path $sourcePath) -and (Test-Path $destinationPath))
{
Write-Host "Copy files from ($sourcePath) to folder ($destinationPath)...`r`n"
Copy-Item "$($sourcePath)\*" $destinationPath -Recurse -Force
Write-Host "Successfully copied files from ($sourcePath).`r`n"
}
}
function StopWindowsService(
[string] $serviceName = $(Throw "Value cannot be null: siteName"))
{
$serviceBefore = Get-Service $serviceName
Write-Host "($serviceName) is now ($serviceBefore.status)...`r`n"
Write-Host "Stopping Windows Service ($serviceName)...`r`n"
Stop-Service $serviceName
Write-Host "Successfully stopped Windows Service ($serviceName)...`r`n"
$serviceAfter = Get-Service $serviceName
Write-Host "($serviceName) is now ($($serviceAfter.status))...`r`n"
}
function StartWindowsService(
[string] $serviceName = $(Throw "Value cannot be null: siteName"))
{
$serviceBefore = Get-Service $serviceName
Write-Host "($serviceName) is now ($serviceBefore.status)...`r`n"
Write-Host "Starting Windows Service ($serviceName)...`r`n"
Start-Service $serviceName
Write-Host "Successfully started Windows Service ($serviceName)...`r`n"
$serviceAfter = Get-Service $serviceName
Write-Host "($serviceName) is now ($($serviceAfter.status))...`r`n"
}
All fine with Start/Stop/Copy New Windows Service Dll's.
But when I try to remove old files after stopping service all of them is locked and I get error:
Remove-Item : Cannot remove item ...\WindowsService\bin\Autofac.dll: Access to the path '...WindowsService\bin\Autofac.dll' is denied.
For all dll files.
May be need to uninstall/install service isnstead of stop/run? Any ideas?
Stopping Service should be enought.
Check the following:
You are using direct pathes to your files
The application or console that runs your script is running under properly priveledged user.
Check the dlls folder security. Check if the user your application running on is priveldged to delete files in the specified folder
I found solution.
First thing: I run this script after installation windows service in stopped status and dll's already was in folder. And first run didn't produce any error. After second run I get the errors.
When I added waiting after stop service and before removing old dll's everything was well:
StopWindowsService $serviceName
Start-Sleep -s 5
RemoveFiles $servicePath
CopyFiles $serviceBinPath $servicePath
StartWindowsService $serviceName
I think that it is because the files have not yet unlocked immediately after stopping service.
Thanks a lot. Sorry for bad english
Related
I created a PowerShell script to create a Virtual Directory and convert it to a WebApplication, with an existing physical path.
It works but I find it strange that the output shows two entries, when converting it to a WebApplication.
Name PhysicalPath
---- ------------
v2 E:\inetpub\MyWebsite\v2
v2 E:\inetpub\MyWebsite\v2
I tried different ways of creating the Virtual Folder and the WebApplication.
function Create-VirtualDirectory-With-AppPool {
Param (
[string] $WebSiteName,
[string] $VirtualFolderName,
[string] $AppPoolName
)
$PhysicalPathWebSite = (Get-Website -Name $WebSiteName | Select-Object).PhysicalPath
$PhysicalPathVirtDir = "$PhysicalPathWebSite\$VirtualFolderName"
Write-Host "The following will be created:"
Write-Host "- Virtual folder: $WebSiteName\$VirtualFolderName with physical path: $PhysicalPathVirtDir"
Write-Host "- Application: IIS:\Sites\$WebSiteName\$VirtualFolderName"
Read-Host "Press enter to continue (Ctrl-c to abort)"
New-WebVirtualDirectory -Site $WebSiteName -Name $VirtualFolderName -PhysicalPath $PhysicalPathVirtDir
# Other attempt, same result:
#New-Item "IIS:\Sites\$WebSiteName\$VirtualFolderName" -type VirtualDirectory -physicalPath $PhysicalPathVirtDir
ConvertTo-WebApplication "IIS:\Sites\$WebSiteName\$VirtualFolderName"
# Other attempt, same result:
#New-Item "IIS:\Sites\$WebSiteName\$VirtualFolderName" -type Application -physicalPath $PhysicalPathVirtDir
# Set AppPool
Set-ItemProperty "IIS:\Sites\$WebSiteName\$VirtualFolderName" -name applicationPool -value $AppPoolName
Write-Host "Done."
}
Am I doing something wrong?
Is there some caching?
It is indeed as Mathias mentioned.
When playing around with piping to | Out-Null for both the Virtual directory and Converting to a WebApplication, I saw the separate outputs.
So, there are two options: discard the output or place the output in a variable and add some text. I choose the last one.
function Create-VirtualDirectory-With-AppPool {
Param (
[string] $WebSiteName,
[string] $VirtualFolderName,
[string] $AppPoolName
)
$PhysicalPathWebSite = (Get-Website -Name $WebSiteName | Select-Object).PhysicalPath
$PhysicalPathVirtDir = "$PhysicalPathWebSite\$VirtualFolderName"
Write-Host "The following will be created:"
Write-Host "- Virtual folder: $WebSiteName\$VirtualFolderName with physical path: $PhysicalPathVirtDir"
Write-Host "- Application: IIS:\Sites\$WebSiteName\$VirtualFolderName"
Read-Host "Press enter to continue (Ctrl-c to abort)"
$OutputNewvDir = New-WebVirtualDirectory -Site $WebSiteName -Name $VirtualFolderName -PhysicalPath $PhysicalPathVirtDir
$OutputConvertApp = ConvertTo-WebApplication "IIS:\Sites\$WebSiteName\$VirtualFolderName"
# Set AppPool
Set-ItemProperty "IIS:\Sites\$WebSiteName\$VirtualFolderName" -name applicationPool -value $AppPoolName
Write-Host "New Virtual directory: $($OutputNewvDir | Format-List | Out-String)"
Write-Host "Convert to Application: $($OutputConvertApp | Format-List | Out-String)"
Write-Host "Done."
}
New Virtual directory:
Name : V2
PhysicalPath : C:\inetpub\wwwroot\MyWebsite\V2
Convert to Application:
Path : /V2
ApplicationPool : DefaultAppPool
EnabledProtocols : http
PhysicalPath : C:\inetpub\wwwroot\MyWebsite\V2
One strange thing is that both commands have a different number of parameters, but some are shown when output together (as shown in my original question).
But I can live with that, will research that later.
I have written below PowerShell script in one server to search for folder existence in other servers.
$Servers = Get-Content C:\scripts\serverlist.txt
foreach ($Server in $Servers) {
$Test = Test-Path -Path "\\$Server\c$\Documents and Settings\"
if ($Test -eq $true) {
Write-Host "Path exists on $Server."
} else {
Write-Host "Path NOT exist on $Server."
}
}
I am getting correct answer if I search for folders present in same server, but if I search for folders present in other server am getting "Path NOT exist on $Server" even though it is present.
Later I tried this one. With this also am facing the same issue
Get-Content c:\Users\jason\Documents\Scripts\Serverlist.txt |
Select-Object #{Name='ComputerName';Expression={$_}},
#{Name='FolderExist';Expression={Test-Path "\\$_\c$\program files\folder"}}
Also, please let me know if there is any method for this using C#.
Please can you any help me ,why powershell keeps throwing below error message
PS C:\Users\Administrator\Desktop> .\Register_dll.cmd
C:\Users\Administrator\Desktop>[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=7f48c3199e5dff41")
The filename, directory name, or volume label syntax is incorrect.
C:\Users\Administrator\Desktop>$publish = New-Object System.EnterpriseServices.Internal.Publish
'$publish' is not recognized as an internal or external command,
operable program or batch file.
C:\Users\Administrator\Desktop>$publish.GacInstall("C:\Users\Administrator\Desktop\Mydll.dll")
'$publish.GacInstall' is not recognized as an internal or external command,
operable program or batch file.
Below is the batch file i have ran in Powershell as Administrator and i have verified the version and publictoken .I guess that is not the issue here.
[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7f48c3199e5dff41")
$publish = New-Object System.EnterpriseServices.Internal.Publish
$publish.GacInstall("C:\Users\Administrator\Desktop\MyDll.dll")
Your script needs to be saved as .ps1. It currently has the extention of .cmd which is making the PowerShell call the old Command shell to execute it which then doesn't recognise the PowerShell commands.
I wrote this a while ago to allow me to remote install GAC assemblies. Save this script as a module (.psm1) or a script (.ps1), import it, and run Install-GACAssembly:
Set-Variable GAC_VS2015_ASSEMBLY_REGKEY -option ReadOnly -value "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319\AssemblyFoldersEx"
[System.Reflection.Assembly]::Load("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a") | Out-Null
function Install-GACAssembly {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[ValidateNotNull()]
[ValidateScript({ Test-Path $_ -PathType Container })]
[string] $AssemblyDir,
[Parameter()]
[switch] $DevMode,
[Parameter()]
[string] $DevRegKeyName,
[Parameter()]
[switch] $uninstall
)
$ErrorActionPreference = "Stop"
if($DevMode -and [string]::IsNullOrWhiteSpace($DevRegKeyName)) {
throw "If `$DevMode is true, a unique folder name must be specified in `$DevRegKeyName i.e. 'MyClient'"
}
if($DevMode) {
New-Item -Path $GAC_VS2015_ASSEMBLY_REGKEY -Name $DevRegKeyName -Value $AssemblyDir -Force | Out-Null
}
$installText = "$(if ($uninstall) { "un" })install"
Write-Verbose "Searching '$AssemblyDir' for GAC .dll files to $installText"
$publisher = New-Object System.EnterpriseServices.Internal.Publish
$assemblies = Get-ChildItem $AssemblyDir -Filter "*.dll"
Write-Verbose #"
Found $($assemblies.Count) .dll files:
$($assemblies.FullName)
"#
$assemblies | % {
if(!$uninstall) {
Write-Verbose " Installing $($_.FullName) into the GAC"
$output = $publisher.GacInstall($_.FullName)
} else {
Write-Verbose " Removing $($_.FullName) from the GAC"
$output = $publisher.GacRemove($_.FullName)
}
}
Write-Verbose "GAC $installText finished"
Write-Verbose "===================================="
}
If you create a module (.psm1) you have to import it into your powershell script / session using Import-Module:
PS D:\> Import-Module -Name "D:\Path-to-module\ModuleFileName.psm1" -Force
Install-GACAssembly -AssemblyDir "D:\Path-to-your-assembly\assembly-name.dll"
You can also use it to uninstall:
PS D:\> Import-Module -Name "D:\Path-to-module\ModuleFileName.psm1" -Force
Install-GACAssembly -AssemblyDir "D:\Path-to-your-assembly\assembly-name.dll" -uninstall
You can see verbose output by using the -Verbose flag on either command.
I found the solution myself for the question.
Firstly as Mark stated we need to run have file extension as .PS1 because it is a PowerShell script.
And then run below command to to successfully register the DLL.
[Reflection.Assembly]::LoadWithPartialName("System.EnterpriseServices") | Out-Null
[System.EnterpriseServices.Internal.Publish] $publish = new-object System.EnterpriseServices.Internal.Publish
$publish.GacInstall("MYdllFile.dll")
I created an High-Trust add-in for SharePoint 2013 with custom ribbon action and custom menu action.
For this, I have an ASP.NET MVC WebSite with the methods in the controller which match with the virtual urls put as custom action url. So, in the different elements.xml files, I filled action urls using the token 'remoteUrl', so no problem with the mapping.
When i create a package with VS2013, I write the url of my website which is on VM reachable from SP Server, and the client ID (I got from SP while registring my app). When I click on 'Finish', VS2013 generates a file '.app' which can be imported in SP online store or SP internal store.
Here is my problem, if I need to change the address of my website (which is stored in the app file, VS2013 just replaces the token 'RemoteUrl' with the url I give to it), is there any clean way to update the app file or may be if possible, directly the app stored in the SP application store (local to the server) ?
I found nothing for this problem. I saw few things about updating app with events and web services, but I didn't understood.
[EDIT] : I didn't understood that I have to change app version each time I need to update it that's why It didn't worked. Also, it seems that there is no other way to update the url in app file than modifying the AppManifest.xml in app file (which is a zip).
In one of my projects we used to do it with the following PowerShell script. It extracted the app file (it's just a ZIP) and modified multiple nodes in the manifest XML.
For packaging it uses a local copy of 7zip.
function ModifyAppPackage($appPackagePath, $applicationUrl, $clientId){
[Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem");
$item = get-item $appPackagePath;
$zipFilePath = Join-Path $item.Directory.FullName $($item.BaseName + ".zip");
Copy-Item $item $zipFilePath;
$unzipDirectory = Join-Path $PSScriptRoot "\Temp";
New-Item -ItemType Directory -Force -Path $unzipDirectory;
if (Test-Path -Path $unzipDirectory\*)
{
Remove-Item $unzipDirectory\* -Force -Confirm:$false -Recurse:$true;
}
[System.IO.Compression.ZipFile]::ExtractToDirectory($zipFilePath, $unzipDirectory);
$modifiedFile = Join-Path $unzipDirectory "modified.txt"
if (Test-Path -Path $modifiedFile)
{
$modifiedContent = Get-Content $modifiedFile
if ($modifiedContent -eq $applicationUrl)
{
Remove-Item $unzipDirectory -Confirm:$false -Recurse:$true;
Remove-Item $zipFilePath;
return;
}
Remove-Item $modifiedFile;
}
$modifiedFileContent = $applicationUrl;
$modifiedFileContent >> $modifiedFile;
$manifestFileName = "AppManifest.xml";
$manifestFilePath = Join-Path $unzipDirectory $manifestFileName;
$manifestXml = [xml](get-content $manifestFilePath);
$nameSpaceManager = New-Object System.Xml.XmlNamespaceManager($manifestXml.NameTable);
$nameSpaceManager.AddNamespace("ns", $manifestXml.DocumentElement.NamespaceURI);
$startPageElement = $manifestXml.SelectSingleNode("/ns:App/ns:Properties/ns:StartPage", $nameSpaceManager);
$StartPage = $applicationUrl + "?{StandardTokens}"
$startPageElement.'#text' = $StartPage
$InstalledEventEndpointElement = $manifestXml.SelectSingleNode("/ns:App/ns:Properties/ns:InstalledEventEndpoint", $nameSpaceManager);
$InstalledEventEndpoint = $applicationUrl + "/Services/AppEventReceiver.svc"
$InstalledEventEndpointElement.'#text' = $InstalledEventEndpoint
$clientIdElement = $manifestXml.SelectSingleNode("/ns:App/ns:AppPrincipal/ns:RemoteWebApplication", $nameSpaceManager);
$clientIdElement.ClientId = $clientId;
$manifestXml.Save($manifestFilePath);
if (Test-Path -Path $zipFilePath)
{
Remove-Item $zipFilePath;
}
$pathToZipExe = $("$PSScriptRoot\7za.exe");
[Array]$arguments = "a", "-tzip", "$zipFilePath", "$unzipDirectory\*.*", "-r";
& $pathToZipExe $arguments;
# Cleanup
Remove-Item $unzipDirectory -Confirm:$false -Recurse:$true;
Remove-Item $appPackagePath -Confirm:$false;
# Rename new zip to .app
Rename-Item $zipFilePath $appPackagePath -Force -Confirm:$false;
return $true;
}
I think it would be possible to store the url in one of custom list in the app. Refer the url from the list. Whenever you need to change the url it can be done from the app itself.
Is it possible to update the value of a setting in an Azure Cloud Service with Azure Powershell?
So far there is no way to update just a single setting (the Service Management API does not allow it - it only accepts the whole service configuration). So, in order to update a single setting, you will have to update the entire configuration. And you can do this with PowerShell:
# Add the Azure Account first - this will create a login promppt
Add-AzureAccount
# when you have more then one subscription - you have explicitly select the one
# which holds your cloud service you want to update
Select-AzureSubscription "<Subscription name with spaces goes here>"
# then Update the configuration for the cloud service
Set-AzureDeployment -Config -ServiceName "<cloud_service_name_goes_here>" `
-Configuration "D:/tmp/cloud/ServiceConfiguration.Cloud.cscfg" `
-Slot "Production"
For the the `-Configuration' parameter I have provided full local path to the new config file I want to use with my cloud service.
This is verified and working solution.
As astaykov says, you can't update a single cloud config value using Powershell.
But you can read all of the settings, update the one you wish to change, save it to a temp file, and then set all the settings again, like so:
UpdateCloudConfig.ps1:
param
(
[string] $cloudService,
[string] $publishSettings,
[string] $subscription,
[string] $role,
[string] $setting,
[string] $value
)
# param checking code removed for brevity
Import-AzurePublishSettingsFile $publishSettings -ErrorAction Stop | Out-Null
function SaveNewSettingInXmlFile($cloudService, [xml]$configuration, $setting, [string]$value)
{
# get the <Role name="Customer.Api"> or <Role name="Customer.NewsletterSubscription.Api"> or <Role name="Identity.Web"> element
$roleElement = $configuration.ServiceConfiguration.Role | ? { $_.name -eq $role }
if (-not($roleElement))
{
Throw "Could not find role $role in existing cloud config"
}
# get the existing AzureServiceBusQueueConfig.ConnectionString element
$settingElement = $roleElement.ConfigurationSettings.Setting | ? { $_.name -eq $setting }
if (-not($settingElement))
{
Throw "Could not find existing element in cloud config with name $setting"
}
if ($settingElement.value -eq $value)
{
Write-Host "No change detected, so will not update cloud config"
return $null
}
# update the value
$settingElement.value = $value
# write configuration out to a file
$filename = $cloudService + ".cscfg"
$configuration.Save("$pwd\$filename")
return $filename
}
Write-Host "Updating setting for $cloudService" -ForegroundColor Green
Select-AzureSubscription -SubscriptionName $subscription -ErrorAction Stop
# get the current settings from Azure
$deployment = Get-AzureDeployment $cloudService -ErrorAction Stop
# save settings with new value to a .cscfg file
$filename = SaveNewSettingInXmlFile $cloudService $deployment.Configuration $setting $value
if (-not($filename)) # there was no change to the cloud config so we can exit nicely
{
return
}
# change the settings in Azure
Set-AzureDeployment -Config -ServiceName $cloudService -Configuration "$pwd\$filename" -Slot Production
# clean up - delete .cscfg file
Remove-Item ("$pwd\$filename")
Write-Host "done"