While utilizing the SharePoint object model (Microsoft.Sharepoint.dll) is a powerful mechanism for doing administration and custom development tasks, anything you write that uses it needs to run on the server hosting WSS or MOSS. This typically includes webparts which, in general, is not a big deal since they have to be installed there anyway's. Admin utilities, on the other hand, are typically where using the OM it starts to become a pain (just ask any server admin to give somebody server/console access because they have to run a certain tool and you will start to see the problems that this might conjure up). But don’t worry, its SharePoint web services to the rescue. By using the SharePoint web services, we can start to develop some admin utility's that we can use for remote SharePoint installations. This multi part post will be about using windows powershell and the SharePoint web services to create a small admin utility for SharePoint administration.
So let’s get started!!!
The first step in this process is creating the web service stubs. You can do this two ways. The first way is to use visual studio and add a web reference, but since this is a post about powershell, we wont focus on that. The second way is to create the stubs using the wsdl.exe to generate a CS wrapper file and csc.exe command to compile that wrapper source file into a .NET DLL.
For example assuming your SharePoint server name is goofy (Yes, I am a Disney fanatic), and you want to generate a C# file from the WSDL definition you would run the following commands.
WSDL.exe http://goofy/_vti_bin/Alerts.asmc?wsdl /out:c:johnalerts.cs (This generates the source file)
csc /type:library /out:c:john.alerts.dll c:johnalerts.cs (This will generate a .NET dll wrapper that you can now use in a .NET application). This process has to be done for each web service you want to talk to.
Since this is a pretty repetitive task, you might be thinking, “Hey,create a script for that!”, so thats exactly what happened. Here is a powershell script auto generates the stub DLL’s. (It also creates the admin site dll’s for use in your projects as well).
There parameters for the script are (or you can just run it from powershell, and it will prompt you)
-CSCCompilerLocation Location of the CSharp Compiler
-WSDLLocation Location of the WSDL.EXE application
-OutputLocation Output File Location
-SharePointServerName Name of your sharepoint server
-SharePointAdminPort Admin port of your sharepoint server
Here is a short video to show this in process.
Video Code Download Script
[flashvideo filename="/wp-content/uploads/2008/06/wrapperdemo.flv" image="/wp-content/uploads/2008/06/pspoweringsp.jpg" height="500" width="800" /]
param(
[string] $CSCCompilerLocation = $(Read-Host "Enter CSC.exe location `n[Enter for default location of 'C:WindowsMicrosoft.NETFrameworkv2.0.50727csc.exe']"),
[string] $WSDLLocation = $(Read-Host "`nEnter WSDL.exe location `n[Enter for default location of 'C:Program FilesMicrosoft.NETSDKv2.0 64bitBinwsdl.exe']"),
[string] $OutputLocation = $(Read-Host "`nEnter location for output files [Enter for default location of 'C:SHAREPOINTSTUFF']"),
[string] $SharePointServerName = $(Read-Host "`nEnter the sharepoint server name [Enter for default location of 'localhost']"),
[int] $SharePointAdminPort = $(Read-Host "`nEnter the sharepoint admin port #"),
[string] $SharePointSite = $(Read-Host "`nEnter a sharepoint site (Ex. http://goofy/site/HR).`n[Enter to cancel the generation of site DLL's and only create the admin wrappers]"),
[string] $Language = $(Read-Host "`nEnter the source file language (CS or VB)`n[Enter for CSharp source files]"),
[string] $DeleteCheck = $(Read-Host "`nAny files located in the output directory will be deleted. Please type OK to continue.")
)
$DeleteCheck = $DeleteCheck.ToUpper()
if ( $DeleteCheck -ne "OK" )
{
exit
}
if ( $CSCCompilerLocation -eq "")
{
$CSCCompilerLocation = "C:WindowsMicrosoft.NETFrameworkv2.0.50727csc.exe"
}
if ( $WSDLLocation -eq "")
{
$WSDLLocation = "C:Program FilesMicrosoft.NETSDKv2.0 64bitBinwsdl.exe"
}
if ( $OutputLocation -eq "")
{
$OutputLocation = "C:SHAREPOINTSTUFF"
}
if ( $SharePointServerName -eq "")
{
$SharePointServerName = "LOCALHOST"
}
if ( $SharePointAdminPort -eq "")
{
$SharePointAdminPort = "11111"
}
if ( $Language -eq "")
{
$Language = "CS"
}
else
{
$Language = $Language.ToUpper()
}
if ( $SharePointSite -ne "" )
{
if ( $SharePointSite.Substring($SharePointSite.Length - 1,1) -ne "/" )
{
$SharePointSite = $SharePointSite + "/"
}
}
#Creating an array al the sharepoint web service files. These will be used later on when
#we construct the URL to create the WSDL file.
$SharepointWebServiceList = "alerts.asmx",
"authentication.asmx",
"copy.asmx",
"dws.asmx",
"forms.asmx",
"imaging.asmx",
"dspsts.asmx",
"lists.asmx",
"meetings.asmx",
"people.asmx",
"permissions.asmx",
"sharepointemailws.asmx",
"sitedata.asmx",
"sites.asmx",
"spsearch.asmx",
"usergroup.asmx",
"versions.asmx",
"views.asmx",
"webpartpages.asmx",
"webs.asmx"
#check to ensure the output location the user inputted was valid. If not the autocreate it.
if ( $dirCheck = Test-Path $OutputLocation )
{
#$existingFiles = Get-ChildItem *.* -Path $OutputLocation
#foreach ($existingFile in $existingFiles )
#{
#$existingFile
# $sourceFileWithPath = $OutputLocation + $existingFile
# Remove-Item $sourceFileWithPath
#}
# exit
}
else
{
#Directory does not exists so auto create it for the user.
New-Item -ItemType Directory -Path $OutputLocation | Out-Null
}
function createAdminWrapperCSSourceFiles ([string]$SharePointServerName,[string]$SharePointAdminPort,[string]$OutputLocation,[array]$SharepointWebServiceList)
{
#Traversing each web service listed in the array (defined above). For each web service
c#we are using the WSDL.exe file to generate the WSDL source files *.cs. Once create these will
#be used to create the dll library's to be used for accessing the sharepoint web services.
Write-Progress -Activity "Creating admin site source files (CS) from WSDL..." -Status "Please be patient"
$progressCount = 0
foreach ( $service in $SharepointWebServiceList)
{
#creating the parameter list to pass into the WSDL.exe.
#exampe of the full path would be
#
wsdl.exe http://spdev/_vti_bin/webs.asmx?wsdl /out:c:johntestwebs.cs
$wsdlParam = "http://" + $SharePointServerName + ":" + $SharePointAdminPort + "/_vti_bin/" + $service + "?wsdl /language:CS /out:" + $OutputLocation + $service.Substring(0,$service.LastIndexOf(".")) + "_admin.cs"
#debug
#$wsdlParam
#Starting a new process for WSDL.exe and passing in the parameter. This will create the source files in the user specific directory.
$wsdlProcessStartInfoObject = New-Object System.Diagnostics.ProcessStartInfo
$wsdlProcessStartInfoObject.FileName = $WSDLLocation
$wsdlProcessStartInfoObject.Arguments = $wsdlParam
$wsdlProcessStartInfoObject.WindowStyle = "Hidden"
$wsdlProcessStartInfoObject.CreateNoWindow = $TRUE
$wsdlProcessStartInfoObject.UseShellExecute = $FALSE
$wsdlProcess = [System.Diagnostics.Process]::Start($wsdlProcessStartInfoObject)
$wsdlProcess.WaitForExit()
$percentComplete = ($progressCount / $SharepointWebServiceList.Count)*100
Write-Progress -Activity "Creating admin site source files (CS) from WSDL..." -Status "Please be patient" -PercentComplete $percentComplete -CurrentOperation "$percentComplete% complete"
$progressCount += 1
}
Write-Progress -Activity "Creating admin site source files (CS) from WSDL..." -Completed -Status "Finished generating .NET wrapper source files."
}
function createAdminWrapperVBSourceFiles ([string]$SharePointServerName,[string]$SharePointAdminPort,[string]$OutputLocation,[array]$SharepointWebServiceList)
{
#Traversing each web service listed in the array (defined above). For each web service
#we are using the WSDL.exe file to generate the WSDL source files *.cs. Once create these will
#be used to create the dll library's to be used for accessing the sharepoint web services.
Write-Progress -Activity "Creating admin site source files (CS) from WSDL..." -Status "Please be patient"
$progressCount = 0
foreach ( $service in $SharepointWebServiceList)
{
#creating the parameter list to pass into the WSDL.exe.
#exampe of the full path would be
#
wsdl.exe http://spdev/_vti_bin/webs.asmx?wsdl /out:c:johntestwebs.cs
$wsdlParam = "http://" + $SharePointServerName + ":" + $SharePointAdminPort + "/_vti_bin/" + $service + "?wsdl /language:CS /out:" + $OutputLocation + $service.Substring(0,$service.LastIndexOf(".")) + "_admin.cs"
#debug
#$wsdlParam
#Starting a new process for WSDL.exe and passing in the parameter. This will create the source files in the user specific directory.
$wsdlProcessStartInfoObject = New-Object System.Diagnostics.ProcessStartInfo
$wsdlProcessStartInfoObject.FileName = $WSDLLocation
$wsdlProcessStartInfoObject.Arguments = $wsdlParam
$wsdlProcessStartInfoObject.WindowStyle = "Hidden"
$wsdlProcessStartInfoObject.CreateNoWindow = $TRUE
$wsdlProcessStartInfoObject.UseShellExecute = $FALSE
$wsdlProcess = [System.Diagnostics.Process]::Start($wsdlProcessStartInfoObject)
$wsdlProcess.WaitForExit()
$percentComplete = ($progressCount / $SharepointWebServiceList.Count)*100
Write-Progress -Activity "Creating admin site source files (CS) from WSDL..." -Status "Please be patient" -PercentComplete $percentComplete -CurrentOperation "$percentComplete% complete"
$progressCount += 1
}
Write-Progress -Activity "Creating admin site source files (CS) from WSDL..." -Completed -Status "Finished generating .NET wrapper source files."
}
function createGeneralWrapperCSSourceFiles ([string]$SharePointSite,[string]$OutputLocation,[array]$SharepointWebServiceList)
{
#Traversing each web service listed in the array (defined above). For each web service
#we are using the WSDL.exe file to generate the WSDL source files *.cs. Once create these will
#be used to create the dll library's to be used for accessing the sharepoint web services.
Write-Progress -Activity "Creating sharepoint site source files (CS) from WSDL..." -Status "Please be patient"
$progressCount = 0
foreach ( $service in $SharepointWebServiceList)
{
#creating the parameter list to pass into the WSDL.exe.
#exampe of the full path would be
#
wsdl.exe http://spdev/_vti_bin/webs.asmx?wsdl /out:c:johntestwebs.cs
$wsdlParam = $SharePointSite + "_vti_bin/" + $service + "?wsdl /language:CS /out:" + $OutputLocation + $service.Substring(0,$service.LastIndexOf(".")) + ".cs"
#Starting a new process for WSDL.exe and passing in the parameter. This will create the source files in the user specific directory.
$wsdlProcessStartInfoObject = New-Object System.Diagnostics.ProcessStartInfo
$wsdlProcessStartInfoObject.FileName = $WSDLLocation
$wsdlProcessStartInfoObject.Arguments = $wsdlParam
$wsdlProcessStartInfoObject.WindowStyle = "Hidden"
$wsdlProcessStartInfoObject.CreateNoWindow = $TRUE
$wsdlProcess = [System.Diagnostics.Process]::Start($wsdlProcessStartInfoObject)
$wsdlProcess.WaitForExit()
$percentComplete = ($progressCount / $SharepointWebServiceList.Count)*100
Write-Progress -Activity "Creating sharepoint site source files (CS) from WSDL..." -Status "Please be patient" -PercentComplete $percentComplete -CurrentOperation "$percentComplete% complete"
$progressCount += 1
}
Write-Progress -Activity "Creating sharepoint site source files (CS) from WSDL..." -Completed -Status "Finished generating .NET wrapper source files."
}
function createGeneralWrapperVBSourceFiles ([string]$SharePointSite,[string]$OutputLocation,[array]$SharepointWebServiceList)
{
#Traversing each web service listed in the array (defined above). For each web service
#we are using the WSDL.exe file to generate the WSDL source files *.cs. Once create these will
#be used to create the dll library's to be used for accessing the sharepoint web services.
Write-Progress -Activity "Creating sharepoint site source files (VB) from WSDL..." -Status "Please be patient"
$progressCount = 0
foreach ( $service in $SharepointWebServiceList)
{
#creating the parameter list to pass into the WSDL.exe.
#exampe of the full path would be
#
wsdl.exe http://spdev/_vti_bin/webs.asmx?wsdl /out:c:johntestwebs.cs
$wsdlParam = "http://" + $SharePointServerName + "/_vti_bin/" + $service + "?wsdl /language:VB /out:" + $OutputLocation + $service.Substring(0,$service.LastIndexOf(".")) + "_admin.cs"
#debug
#$wsdlParam
#Starting a new process for WSDL.exe and passing in the parameter. This will create the source files in the user specific directory.
$wsdlProcessStartInfoObject = New-Object System.Diagnostics.ProcessStartInfo
$wsdlProcessStartInfoObject.FileName = $WSDLLocation
$wsdlProcessStartInfoObject.Arguments = $wsdlParam
$wsdlProcessStartInfoObject.WindowStyle = "Hidden"
$wsdlProcessStartInfoObject.CreateNoWindow = $TRUE
$wsdlProcess = [System.Diagnostics.Process]::Start($wsdlProcessStartInfoObject)
$wsdlProcess.WaitForExit()
$percentComplete = ($progressCount / $SharepointWebServiceList.Count)*100
Write-Progress -Activity "Creating sharepoint site source files (VB) from WSDL..." -Status "Please be patient" -PercentComplete $percentComplete -CurrentOperation "$percentComplete% complete"
$progressCount += 1
}
Write-Progress -Activity "Creating sharepoint site source files (VB) from WSDL..." -Completed -Status "Finished generating .NET wrapper source files."
}
function compileSourceFile ([string]$SourceFileType,[string]$OutputLocation)
{
$fileSpec = "*." + $SourceFileType
$gendFiles = Get-ChildItem $fileSpec -Path $OutputLocation
$progressCount = 0
$progressReport = "Compiling (" + $SourceFileType + ") source files to DLL for use in powershell/Visual Studio..."
Write-Progress -Activity $progressReport -Status "Please be patient"
foreach ($file in $gendFiles )
{
$fileWithPath = $OutputLocation + $file
$itemFile = Get-Item $fileWithPath
$CSCCompilerArgs = "/target:library /out:" + $itemFile.FullName.Substring(0,$itemFile.FullName.LastIndexOf(".")) + ".dll " + $itemFile.FullName
#run the compiler on each file to create the dll
$cscProcessStartInfoObject = New-Object System.Diagnostics.ProcessStartInfo
$cscProcessStartInfoObject.FileName = $CSCCompilerLocation
$cscProcessStartInfoObject.Arguments = $CSCCompilerArgs
$cscProcessStartInfoObject.WindowStyle = "Hidden"
$cscProcessStartInfoObject.CreateNoWindow = $TRUE
$cscProcess = [System.Diagnostics.Process]::Start($cscProcessStartInfoObject)
$cscProcess.WaitForExit()
#delete the source CS WSDL file.
Remove-Item $itemFile.FullName
$percentComplete = ($progressCount / $gendFiles.Count)*100
Write-Progress -Activity $progressReport -Status "Please be patient" -PercentComplete $percentComplete -CurrentOperation "$percentComplete% complete"
$progressCount += 1
}
Write-Progress -Activity $progressReport -Completed -Status "Finished compiling"
}
switch ( $Language)
{
"CS"
{
createAdminWrapperCSSourceFiles -SharePointServerName $SharePointServerName -SharePointAdminPort $SharePointAdminPort -OutputLocation $OutputLocation -SharepointWebServiceList $SharepointWebServiceList
if ( $SharePointSite -ne "" )
{
createGeneralWrapperCSSourceFiles -SharePointSite $SharePointSite -OutputLocation $OutputLocation -SharepointWebServiceList $SharepointWebServiceList
}
compileSourceFile -SourceFileType $Language -OutputLocation $OutputLocation
}
"VB"
{
createAdminWrapperVBSourceFiles -SharePointServerName $SharePointServerName -SharePointAdminPort $SharePointAdminPort -OutputLocation $OutputLocation -SharepointWebServiceList $SharepointWebServiceList
if ( $SharePointSite -ne "" )
{
createGeneralWrapperVBSourceFiles -SharePointSite $SharePointSite -OutputLocation $OutputLocation -SharepointWebServiceList $SharepointWebServiceList
}
compileSourceFile -SourceFileType $Language -OutputLocation $OutputLocation
}
default {}
}
Write-Host "Succussfully created all web service wrapper dll's"
This post was about generating the DLL wrappers for use in other powershell postings so keep your eye for for more powershell scripts be posted here.
NOTE: Since i have not signed this script, you will need to set the execution policy to unrestricted.
For Example set-executionpolicy unrestricted