PowerShell : Déploiement d’une infrastructure SharePoint

Comme promis suite à l’IT Camp “SQL Server /SharePoint/Windows Intune, les scénarios d’usage en mode Cloud hybride” du mercredi 18 Septembre 2013, voici le script PowerShell permettant le déploiement automatique des machines virtuelles dans le Cloud Azure. Le script va déployer l’infrastructure ci-dessous. La machine SQL comportera un disque pour les données et un disque pour les journaux de transactions. Les binaires de SharePoint seront installés, mais il sera nécessaire de terminer manuellement l’installation via l’assistant de SharePoint.

clip_image001

Les pré-requis pour faire fonctionner le script sont les suivants :

Cet article est composé de la manière suivante :

  1. Création d’un service de Cloud
  2. Création d’un réseau virtuel
  3. Le script

Création du service de Cloud

Après s’être connecté au portail Azure (https://manage.windowsazure.com), cliquez sur le bouton « + Nouveau »

clip_image002

Dans le menu « Nouveau », cliquez sur « Calcul | Service de Cloud computing | création rapide ». Puis renseignez les champs « URL » et « Région ou groupes d’affinités »

clip_image003

Le nouveau service de Cloud apparait alors dans la liste des services de Cloud. Dans cet exemple, mon service de Cloud se nomme « AutoDeployFr ».

clip_image004

Création du réseau Virtuel

Cliquez sur le bouton « + Nouveau », puis sur « Services de réseau | Réseau virtuel | Création personnalisée »

clip_image006

Dans la première fenêtre « Créer un réseau virtuel », donnez un nom à votre réseau et déterminez un groupe d’affinités. Puis cliquez sur la flèche en bas à droite.

clip_image008

Dans la deuxième fenêtre, définissez un DNS. Dans cet exemple j’ai défini un DNS avec le nom « AutoDeployDNS » et une adresse IP 192.168.0.4. Puis cliquez sur la flèche en bas à droite.

clip_image010

Dans la troisième fenêtre définissez les adresses de votre réseau et de vos sous réseaux. Cliquez sur clip_image012 pour valider la création du réseau virtuel.

Attention, les noms des sous réseaux seront utilisés dans le script.

clip_image014

Voici une copie du réseau virtuel que j’ai créé pour cet exemple.

clip_image015

Le script

Voici le script que j’ai essayé de commenter au maximum. Avant d’exécuter le script, vérifiez que le nom des images virtuelles n’a pas changé entre temps.

Pour ce faire utilisez la commande Power Shell : Get-AzureVMImage | select Image. Puis mettez éventuellement à jour le nom des images virtuelles. Ci-dessous un exemple de nom des images :

clip_image016

Pensez aussi à renommer les différentes variables.

Le script donc Sourire :

#Script de déploiement de machines SharePoint et SQL avec AD et 1 compte d'installation
cls

# Si le fichier Azure.psd1 est manquant, Windows Azure PowerShell est téléchargeable ici:
# https://go.microsoft.com/?linkid=9811175&clcid=0x409
Import-Module "C:\Program Files (x86)\Microsoft SDKs\Windows Azure\PowerShell\Azure\Azure.psd1"

#region Configuration du compte AZURE à utiliser
    #Le fichier PublishSettings peut se récupérer sur ce site "https://windows.azure.com/download/publishprofile.aspx"
    Import-AzurePublishSettingsFile 'C:\Users\franmer\Documents\PowerShell\PublishSettings\MS'
    Set-AzureSubscription -SubscriptionName 'Windows Azure Internal Consumption' -CurrentStorageAccount franmerstorage
    Select-AzureSubscription -SubscriptionName 'Windows Azure Internal Consumption'
#endregion

#region déclaration des paramètres
    # Définition du ServiceName et du réseau virtuel (déjà existants dans Azure)
    $serviceName = 'AutoDeployFr'
    $virtualNetworkName = 'AutoDeployNetwork'

    #Renseignement des sous-réseaux présents dans le réseau virtuel Azure.
    #Dans cet exemple, le réseau "AutoDeployNetWork" dispose de 3 sous réseaux "DCSubnet", "SQLSubnet", "SP2013Subnet"
    #Le nom de ces subnets doivent être identique à ceux de votre réseau virtuelle crée via le portail Azure
    $AzureDCSubNet = 'DCSubnet'
    $SQLSubnet ='SQLSubnet'
    $SPSubnet = 'SP2013Subnet'
 

    #Définition du nom de l'administrateur du domaine et du nom du domaine
    $adminUsername = 'franmer'
    $adminPassword='Pass@word1'
    $domainName = 'ITCamp.demo.com'
    $ShortDomainName = 'ITCamp'
   

    #Définition du compte d'installation de SQL et SharePoint
    $InstallUser = 'InstallUserfranmer'
    $PassWordInstallUser = 'Pass@word1'
    $SecureStringPassWordInstallUser = ConvertTo-SecureString –String $PassWordInstallUser –AsPlainText -Force

    #Définition des images à utiliser
    #les images peuvent être récupérées avec la commande : Get-AzureVMImage | select ImageName
     #ATTENTION, les noms des images peuvent changer en fonction des mises à jour !!
    $WindowsServer2012ImageName = 'bd507d3a70934695bc2128e3e5a255ba__RightImage-Windows-2012-x64-v13.4.12.2'
     $WindowsAndSqlServerImageName = 'fb83b3509582419d99629ce476bcb5c8__Microsoft-SQL-Server-2012SP1-Enterprise-CY13SU04-SQL2012-SP1-11.0.3350.0-Win2012'
    $WindowsandSharePoint2013Trial = 'c6e0f177abd8496e934234bd27f46c5d__SharePoint-2013-Trial-9-18-2013'
   

    #Définition du domaine controlleur
    $DcVmName = 'ITCampDC1'   
    $FullDomainName = 'ITCamp.demo.com'
    $DCVMSize = 'Small'
    $AvailabilitySetName = 'ITCampDC'

    #Définition de la machine SQL      
    $SQLVMSize ='Medium'
    $SQLprefix = 'ITCampSQL'
    $SizeSQLDataDisk = 100  #Gb
    $SizeSQLLogsDisk = 100 #Gb
    $defaultSqlDataFolder = ':\FranmerDATA'  #Sans la lettre du disque
    $defaultSqlLogsFolder = ':\FranmerLOGS'   #Sans la lettre du disque
    $installerDatabaseUsername = $ShortDomainName + "\" + $InstallUser
    $installerDatabasePassword = 'Pass@word1'
    $installerDomainUsername = $ShortDomainName + '\franmer'
    $NbSQLServer = 1
   
    Write-Host $installerDatabaseUsername
    Write-Host $installerDomainUsername

    #Définition de la machine SharePoint
    $SPprefix = 'ITCampSP'   
    $LBSetName = 'SPWebLB'
    $SPVMSize = 'Medium'
    $NbSPServer = 1
   
    #Conversion de adminPassword en secureString
    $SecureStringadminPassword = ConvertTo-SecureString –String $adminPassword –AsPlainText -Force
    $credential = New-Object –TypeName System.Management.Automation.PSCredential –ArgumentList $adminUsername, $SecureStringadminPassword
   
   
   
       
    #Création d'un collection vide d'images virtuelles
    $vms = @()
#endregion

#region create domain controller
     $StartTime = Get-Date
    write-host "début à : " $StartTime
     Write-Host "creating $DcVmName"
    $adminPort = 52101

    #create a new VM Config
    $newVM = `
        New-AzureVMConfig -ImageName $WindowsServer2012ImageName -InstanceSize $DCVMSize -Name $DcVmName `
            -AvailabilitySetName $AvailabilitySetName -DiskLabel "${DcVmName}os" `
            -HostCaching ReadWrite -Label "$DcVmName" |
        Add-AzureProvisioningConfig -Windows -AdminUsername $adminUsername -Password $adminPassword -NoRDPEndpoint |
        Add-AzureDataDisk -CreateNew -DiskSizeInGB 30 -DiskLabel "${DcVmName}data1" -LUN 0 |
        Add-AzureEndpoint -LocalPort 3389 -Name "RDP" -Protocol tcp -PublicPort $adminPort |
        Set-AzureSubnet $AzureDCSubNet
   
    #add the VM config to the collection
    $vms += ,$newVM

    #show the collection
    $vms | format-table

    #create the VM and wait for boot
    New-AzureVM -ServiceName $serviceName -VMs $vms -VNetName $virtualNetworkName -WaitForBoot
    Start-Sleep -Seconds 60
#endregion

#region function definition for PowerShell remoting
    write-host "Definition for PowerShell remoting"
    function InstallWinRMCert($serviceName, $vmname)
    {
        $winRMCert = (Get-AzureVM -ServiceName $serviceName -Name $vmname | select -ExpandProperty vm).DefaultWinRMCertificateThumbprint

        $AzureX509cert = Get-AzureCertificate -ServiceName $serviceName -Thumbprint $winRMCert -ThumbprintAlgorithm sha1

        $certTempFile = [IO.Path]::GetTempFileName()
        Write-Host $certTempFile
        $AzureX509cert.Data | Out-File $certTempFile

        # Target The Cert That Needs To Be Imported
        $CertToImport = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $certTempFile

        $store = New-Object System.Security.Cryptography.X509Certificates.X509Store "Root", "LocalMachine"
        $store.Certificates.Count
        $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
        $store.Add($CertToImport)
        $store.Close()

        Remove-Item $certTempFile
    }
#endregion

#region Installation des fonctionnalités sur le DC
    #Installation de ADDS
    write-host "Installation de ADDS"
    $uri = Get-AzureWinRMUri -ServiceName $serviceName -Name $DcVmName
    InstallWinRMCert $serviceName $DcVmName

        # Utilisation du PowerShell dans la machine virtuelle distante (le domaine controlleur)
    Invoke-Command -ConnectionUri $uri.ToString() -Credential $credential `
        -ArgumentList $SecureStringadminPassword -ScriptBlock `
    {
       
        param($SecureStringadminPassword)

        $logLabel = $((get-date).ToString("yyyyMMddHHmmss"))
         $logPath = "$env:TEMP\init-webservervm_webserver_install_log_$logLabel.txt"
        Import-Module -Name ServerManager
         Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools -LogPath $logPath

        $disks = Get-Disk | where { $_.NumberOfPartitions -eq 0 }
        foreach ($d in $disks)
        {
            # there should be one disk only
             $diskNumber = $d.Number
            echo "will format disk $diskNumber"
            Initialize-Disk $diskNumber
            New-Partition -DiskNumber $diskNumber -UseMaximumSize -AssignDriveLetter
            Format-Volume -DriveLetter F -Confirm:$False
            get-volume -DriveLetter F
        }

        Import-module ADDSDeployment
        Install-ADDSForest -DomainName "ITCamp.demo.com" -InstallDns:$true -DatabasePath "F:\NTDS" `
             -LogPath "F:\NTDS" -SysvolPath "F:\SYSVOL" -NoRebootOnCompletion:$false -Force:$true `
            -SafeModeAdministratorPassword $SecureStringadminPassword
    }
#endregion

#region wait for reboot and start a new collection
    Start-Sleep -Seconds 60

    $DcVm = Get-AzureVM -ServiceName $serviceName -Name $DcVmName
    While ($DcVm.InstanceStatus -ne "ReadyRole")
    {
         write-host "Waiting for DC to be ready... Current Status = " $DcVm.InstanceStatus
        Start-Sleep -Seconds 15
        $DcVm = Get-AzureVM -ServiceName $serviceName -Name $DcVmName
     }

    $vms = @()
#endregion

#region Ajout d'un compte utilisateur dans l'AD pour réaliser les installations de SQL Server et SharePoint

    write-host "Ajout d'un utilisateur dans le domaine"
    Invoke-Command -ConnectionUri $uri.ToString() -Credential $credential -ArgumentList $InstallUser, $SecureStringPassWordInstallUser -ScriptBlock {
    param($InstallUser , $SecureStringPassWordInstallUser)
    
        #$pwd = ConvertTo-SecureString "Pass@word1" -AsPlainText -Force
        New-ADUser -Name $InstallUser  -AccountPassword  $SecureStringPassWordInstallUser -PasswordNeverExpires $true  -ChangePasswordAtLogon $false  -Enabled $true

    }

#endregion

#================================================================================================================

#region Installation de SQL Server

for($i=1; $i -le $NbSQLServer; $i++)
{
    Write-Host "creating $SQLprefix${i}"
     $adminPort = 53100 + $i

    #Création de la configuration de la VM
    $newVM = `
        New-AzureVMConfig -ImageName $WindowsAndSqlServerImageName -InstanceSize $SQLVMSize -Name "$SQLprefix$i" `
            -AvailabilitySetName "$SQLprefix" -DiskLabel "$SQLprefix${i}os" `
            -HostCaching ReadWrite -Label "$SQLprefix${i}" |
        Add-AzureProvisioningConfig -WindowsDomain -AdminUsername $adminUsername -Password $adminPassword `
         -Domain $ShortDomainName -DomainUserName $adminUsername -DomainPassword $adminPassword -JoinDomain $domainName `
        -NoRDPEndpoint |
        Add-AzureDataDisk -CreateNew -DiskSizeInGB $SizeSQLDataDisk -LUN 0 -DiskLabel "$SQLprefix${i}Data" |
         Add-AzureDataDisk -CreateNew -DiskSizeInGB $SizeSQLLogsDisk -LUN 1 -DiskLabel "$SQLprefix${i}Logs" |
        Add-AzureEndpoint -LocalPort 3389 -Name "RDP" -Protocol tcp -PublicPort $adminPort |
        Set-AzureSubnet $SQLSubnet
   
    #add the VM config to the collection
    $vms += ,$newVM
}
#endregion

#region SharePoint Server

for($i=1; $i -le $NbSPServer; $i++)
{
    Write-Host "creating $SPprefix$i"
    $adminPort = 52200 + $i

    #Création de la configuration de la VM
    $newVM = `
        New-AzureVMConfig -ImageName $WindowsandSharePoint2013Trial -InstanceSize $SPVMSize -Name "$SPprefix$i" `
            -AvailabilitySetName "$SPprefix" -DiskLabel "$SPprefix${i}os" `
            -HostCaching ReadWrite -Label "$SPprefix${i}" |
       
       
        Add-AzureProvisioningConfig -WindowsDomain -AdminUsername $adminUsername -Password $adminPassword `
        -Domain $ShortDomainName -DomainUserName $adminUsername -DomainPassword $adminPassword -JoinDomain $domainName `
        -NoRDPEndpoint |
        Add-AzureDataDisk -CreateNew -DiskSizeInGB 50 -LUN 0 -DiskLabel "$SPprefix${i}data1" |
        Add-AzureEndpoint -LocalPort 3389 -Name "RDP" -Protocol tcp -PublicPort $adminPort |
         Add-AzureEndpoint -LocalPort 80 -Name "Web" -Protocol tcp -PublicPort 80 -LBSetName $LBSetName -ProbePort 8080 -ProbeProtocol http -ProbePath '/' |
        Set-AzureSubnet $SPSubnet
   
     #Rajout de la VM dans le collection
    $vms += ,$newVM
}
#endregion

#region create SharePoint and SQL Server VMs and wait for them to boot
#show the collection
$vms | format-table

#create the VM and wait for boot
New-AzureVM -ServiceName $serviceName -VMs $vms -WaitForBoot
#endregion

#region install features on SharePoint Servers

for($i=1; $i -le $NbSPServer; $i++)
{
    $vmName = "$SPprefix$i"

    $uri = Get-AzureWinRMUri -ServiceName $serviceName -Name $vmName
    InstallWinRMCert $serviceName $vmName

    # Use native PowerShell Cmdlet to execute a script block on the remote virtual machine
    Invoke-Command -ConnectionUri $uri.ToString() -Credential $credential -ScriptBlock `
    {
         $logLabel = $((get-date).ToString("yyyyMMddHHmmss"))
        $logPath = "$env:TEMP\init-webservervm_webserver_install_log_$logLabel.txt"
        Import-Module -Name ServerManager
        Install-WindowsFeature -Name Web-Server -IncludeAllSubFeature -IncludeManagementTools -LogPath $logPath
    }
}
#endregion

#region Rajout d'un compte d'installation du domaine dans la machine virtuelle SQL   

#$vmType = 'Small'
#$highAvailabilityType = 'None'

    $InstallUser = 'InstallUserfranmer'
    $PassWordInstallUser = 'Pass@word1'

for($i=1; $i -le $NbSQLServer; $i++)
{
$uriSQL = Get-AzureWinRMUri -serviceName $serviceName -Name $SQLprefix${i}

Invoke-Command -ConnectionUri $uriSQL.ToString() -Credential $credential -ArgumentList $installerDatabaseUsername, $installerDatabasePassword, $installerDomainUsername, $defaultSqlDataFolder,
$defaultSqlLogsFolder -ScriptBlock {
            
param($installerDatabaseUsername, $installerDatabasePassword, $installerDomainUsername, $defaultSqlDataFolder, $defaultSqlLogsFolder)
     Import-Module ServerManager  
    Set-ExecutionPolicy Unrestricted
       net localgroup administrators "$installerDomainUsername" /Add
       Start-Sleep -Seconds 20

        # Formatage des disques durs
        Write-host "Formatage des disques durs"
        for($i=2; $i -le 3; $i++)
       
        {
            
            Initialize-Disk -Number $i -PartitionStyle MBR
             $NewPartition = New-Partition -DiskNumber $i -UseMaximumSize -AssignDriveLetter
           
            if ($i -match 2)
            {
                Write-Host "Formatage du disque des données"        
                $SQLPath = $NewPartition.DriveLetter + $defaultSqlDataFolder
                $DataDiskLetter = $NewPartition.DriveLetter                       
                
            }
            Else
            {
                 Write-Host "Formatage du disque des journaux de transactions"
                $SQLPath = $NewPartition.DriveLetter + $defaultSqlLogsFolder
                $LogsDiskLetter = $NewPartition.DriveLetter                  
            
            }

            Format-Volume -DriveLetter $NewPartition.DriveLetter -FileSystem NTFS -NewFileSystemLabel $SQLPath -Confirm:$False           
           
        }

      
             Write-Host "Configuring firewall..."
             netsh advfirewall firewall add rule name='SQL Server (TCP-In)' program='C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Binn\sqlservr.exe' dir=in action=allow protocol=TCP
             Write-Host "Firewall configured."
                                 
              Write-Host "Configuring database permissions and options..."
             Import-Module "sqlps" -Verbose
             Write-Host "Module sqlps importé"
       
        Invoke-Sqlcmd -ServerInstance $env:COMPUTERNAME -Database master -Query `
              "         
        USE [master]
        IF Not EXISTS (SELECT name FROM master.sys.server_principals WHERE name = '$installerDatabaseUsername')
        BEGIN
                 CREATE LOGIN [$installerDatabaseUsername] WITH PASSWORD='$installerDatabasePassword'
                 EXEC sp_addsrvrolemember '$installerDatabaseUsername', 'dbcreator'
                    EXEC sp_addsrvrolemember '$installerDatabaseUsername', 'securityadmin'
         END
       
        IF Not EXISTS (SELECT name FROM master.sys.server_principals WHERE name = '$installerDomainUsername')
         BEGIN
                 CREATE LOGIN [$installerDomainUsername] FROM WINDOWS
                 EXEC sp_addsrvrolemember '$installerDomainUsername', 'sysadmin'
        END     
        EXEC sp_addsrvrolemember 'NT AUTHORITY\SYSTEM', 'sysadmin'
        "

      
             Invoke-Sqlcmd -ServerInstance $env:COMPUTERNAME -database master -Query `
             "USE [master]
              GO
             sp_configure 'show advanced options', 1;RECONFIGURE WITH OVERRIDE;
             GO
             sp_configure 'max degree of parallelism', 1;RECONFIGURE WITH OVERRIDE;
              GO"
             Write-Host "Database configured."

             Write-Host "Enabling mixed authentication mode and setting folder locations..."
             $s = new-object ('Microsoft.SqlServer.Management.Smo.Server') $env:COMPUTERNAME
              $s.Settings.LoginMode = [Microsoft.SqlServer.Management.Smo.ServerLoginMode]::Mixed
             if(-not [string]::IsNullOrEmpty($defaultSqlDataFolder))
             {
                     mkdir $DataDiskLetter$defaultSqlDataFolder
                    $s.Settings.DefaultFile = $DataDiskLetter+$defaultSqlDataFolder
             }
             if(-not [string]::IsNullOrEmpty($defaultSqlLogsFolder))
             {
                    mkdir $LogsDiskLetter$defaultSqlLogsFolder
                    $s.Settings.DefaultLog = $LogsDiskLetter+$defaultSqlLogsFolder
              }

             $s.Alter()
            
             Write-Host "Redémarrage service SQL (2)"
             Restart-Service -Name MSSQLSERVER -Force
             Write-Host "Mixed authentication mode enabled and folder locations set."
      

}
}
#endregion

$EndTime = Get-Date
Write-host "Fin à : "$EndTime

Sources :

Au plaisir de vous voir lors d’un IT Camp!

Franck Mercier

Pour tester Windows Server 2012, Windows 8, SQL Server 2012 et SQL Server 2014 CTP1, vous pouvez télécharger gratuitement la version d’évaluation disponible sous la forme :

· Windows Server 2012 :

· SQL Server 2012 :

· Evaluation SQL Server 2014 CTP1 :

· Testez Azure gratuitement pendant un mois :