Ridurre un disco VHD o VHDX in Hyper-V da PowerShell

Dopo aver tribolato per mezza giornata cercando di ridimensionare un disco in Hyper-V utilizzando gli strumenti della GUI, sono passato a PowerShell e da li ci sono riuscito senza incorrere in problemi di spazio disco e di permessi, e in metà del tempo stimato dall’interfaccia grafica, specie per ridimensionare la partizione.

I passaggi sono:

1. Ferma la VM

2. Monta il VHD con il comando mount-vhd dalla linea di comando:

mount-vhd path\drive.vhdx -passthru | get-disk | get-partition | get-volume
Questo comando fornisce tutte le informazioni relative alle partizioni contenute nel VHD, compreso la lettera del disco, la partizione di avvio (NON RIDIMENSIONARLA) e lo spazio recuperabile.

3. Ora puoi eseguire resize-partition, che ridurrà la partizione alla dimensione desiderata.

resize-partition –driveletter E -size 100GB
-driveletter è la lettera del disco che troviamo con il primo comando, –size è la dimensione a cui vogliamo portare la partizione.

4. Quindi smontiamo il disco con dismount-vhd:

dismount-vhd path\drive.vhdx

5. L’ultimo comando serve a ridimensionare il VHD:

resize-vhd path\drive.vhdx -ToMinimumSize

Questa operazione non è possibile se il disco è VHD, devi prima convertirlo in VHDX:

Convert-VHD path\drive.vhd path\drive.vhdx

Quest’ultima operazione la puoi fare anche da Hyper-V Manager.

E venne il giorno… the database principal owns a schema in the database and cannot be dropped

E’ da qualche settimana che procastino la migrazione dei sistemi su SqlServer 2014 e questo weekend è risultato la scelta migliore anche grazie a all’accavallamento con il 1° maggio che ha garantito traffico zero (o quasi) sui nostri sistemi.

Spostare i DB non è di per se un grande problema, ma per ridurre al dba2minimo il tempo di “down” su alcuni servizi minori non ridondati, nel fare i test ho riscontrato qualche difficoltà nel rimappare schemi e utenti, che anche a parità di nome e password non corrispondono comunque una volta che il DB viene riconnesso.

Per evitare di ricollegare tanti piccoli DB a mano cambiano schemi e utenti, mi sono imbattuto in un’utilissima Stored Procedure che semplifica di molto la vita.

Infatti non basta “droppare” l’utente, perché se c’è uno schema collegato, l’operazione è ben più complicata e tediosa, e riceveremo errori del tipo “the database principal owns a schema in the database and cannot be dropped“.

Invece utilizzando questa stored procedure “Script to Drop All Orphaned SQL Server Database Users” l’operazione diventa estremamente rapita, e può essere lanciata su tutti i DB ricollegati in un colpo solo con il comando:

EXEC sp_msforeachdb 'USE [?]; EXEC sp_Drop_OrphanedUsers'

Un time saver eccezionale, se dovete fare una migrazione massiva.

Copio la stored qualora il sito dovesse scomparire:

use [master]
go
create proc dbo.sp_Drop_OrphanedUsers
as
begin
set nocount on
-- get orphaned users
declare @user varchar(max)
declare c_orphaned_user cursor for
select name
from sys.database_principals
where type in ('G','S','U')
and authentication_type<>2 -- Use this filter only if you are running on SQL Server 2012 and major versions and you have "contained databases"
and [sid] not in ( select [sid] from sys.server_principals where type in ('G','S','U') )
and name not in ('dbo','guest','INFORMATION_SCHEMA','sys','MS_DataCollectorInternalUser') open c_orphaned_user
fetch next from c_orphaned_user into @user
while(@@FETCH_STATUS=0)
begin
-- alter schemas for user
declare @schema_name varchar(max)
declare c_schema cursor for
select name from sys.schemas where USER_NAME(principal_id)[email protected]
open c_schema
fetch next from c_schema into @schema_name
while (@@FETCH_STATUS=0)
begin
declare @sql_schema varchar(max)
select @sql_schema='ALTER AUTHORIZATION ON SCHEMA::['[email protected]_name+ '] TO [dbo]'
print @sql_schema
exec(@sql_schema)
fetch next from c_schema into @schema_name
end
close c_schema
deallocate c_schema

-- alter roles for user
declare @dp_name varchar(max)
declare c_database_principal cursor for
select name from sys.database_principals
where type='R' and user_name(owning_principal_id)[email protected]
open c_database_principal
fetch next from c_database_principal into @dp_name
while (@@FETCH_STATUS=0)
begin
declare @sql_database_principal varchar(max)
select @sql_database_principal ='ALTER AUTHORIZATION ON ROLE::['[email protected]_name+ '] TO [dbo]'
print @sql_database_principal
exec(@sql_database_principal )
fetch next from c_database_principal into @dp_name
end
close c_database_principal
deallocate c_database_principal

-- drop roles for user
declare @role_name varchar(max)
declare c_role cursor for
select dp.name--,USER_NAME(member_principal_id)
from sys.database_role_members drm
inner join sys.database_principals dp
on dp.principal_id= drm.role_principal_id
where USER_NAME(member_principal_id)[email protected]
open c_role
fetch next from c_role into @role_name
while (@@FETCH_STATUS=0)
begin
declare @sql_role varchar(max)
select @sql_role='EXEC sp_droprolemember N'''[email protected]_name+''', N'''[email protected]+''''
print @sql_role
exec (@sql_role)
fetch next from c_role into @role_name
end
close c_role
deallocate c_role

-- drop user
declare @sql_user varchar(max)
set @sql_user='DROP USER ['[email protected] +']'
print @sql_user
exec (@sql_user)
fetch next from c_orphaned_user into @user
end
close c_orphaned_user
deallocate c_orphaned_user
set nocount off
end
go
-- mark stored procedure as a system stored procedure
exec sys.sp_MS_marksystemobject sp_Drop_OrphanedUsers
go

Missing in action…

E’ da più di un anno che non scrivo più sul blog, e devo dire ce mi dispiace, ma il tempo è tiranno e non riesco a dedicargliene più.

Tra il lavoro, la famiglia e lo “studio” per tenermi aggiornato sulle ultime tecnologie, di tempo ne rimane ben poco.
D’altronde bisogna scegliere a cosa dedicarsi, e ultimamente mi sto rendendo conto che il tempo per imparare è sempre troppo poco, e di cose nuove da sapere ne escono più di quante è umanamente possibile apprendere.
Quindi per il momento il mio sforzo è tutto incentrato sulla ricerca e sviluppo più che sulla divulgazione.
Mi dispiace caro Blog, devi avere pazienza, prima o poi torno.

La strategia di Microsoft per eliminare del tutto Windows server 2003

Purtroppo ci sono ancora molti clienti che hanno server Windows 2003, e di certo non si possono obbligare a buttare via tutto per installare il Framework 4.5 che non va con questo OS.
Ci siamo detti “poco male” e “porca Microsoft”, rinuciamo a tutte le nuove chicche di questo FW, e ci teniamo il 4.0 almeno per i prossimi 3 anni.
Invece questo piano è fallito perchè oggi ho scoperto che dal 2015 non si potranno più ottenere certificati in SHA-1, e per le authority diventerà obbligatoria l’emissione di certificati in SHA-2.
Qual’è il problema? Beh se leggiamo sul sito di M$, troviamo questa frase:

“.NET Framework 4.5 has chosen SHA-256 algorithm to sign the manifest by default. However, SHA-1 is used by .NET Framework 4.0. We may get a CryptographicException telling that “the manifest may not be valid or the file could not be opened” when running a ClickOnce 4.5 application on a machine with only .NET Framework 4.0 installed.”

Ora collegando i puntini, viene fuori che senza FW 4.5 non si può leggere certificati SHA-2, che dal 2015 saranno obbligatori.
Quindi come risultato man mano che il prossimo anno i certificati di Code-Sign saranno rinnovati, le applicazioni tipo Click-Once non si installeranno più, con buona pace di tutti i clienti.

A caccia di opportunità per fare il budget

Quando si arriva a fine trimestre spesso ci si trova sotto budget, e bisogna andare a caccia di nuove opportunità con cui realizzarlo.
OPPORTUNITY

Quello che pochi fanno invece è andare a rivedere le opportunità perse nell’ultimo periodo. È vero che quest’opportunità sono perse, però ci sono molti fattori che ne possono influenzare un revival.
Ad esempio il cliente può aver visto una serie di altre presentazioni o fatto una serie incontri con la concorrenza che non hanno portato ai risultati attesi, oppure quando lo avete contattato voi i tempi non erano ancora maturi ed ora possono aver cambiato idea.
Per questo è importante classificare le motivazioni che portano alla perdita dell’opportunità. Quando vado a definirla come “persa” Tustena CRM ci chiede di inserire anche il motivo Di mancata vendita. È classificando correttamente questi motivi che si può avere dei filtri molto efficienti per andare a recuperare potenziali vendite con il minimo sforzo.
Andare in callback su un’opportunità mancata ha anche un effetto sorpresa sul cliente che ha scartato la vostra offerta, ma che a distanza di mesi non ha ancora preso una decisione, e magari ha avuto modo di realizzare inconsciamente il valore di quanto voi gli avevate offerto.
Ora invece potrebbe essere positivamente meravigliato di quanto voi siete solerti ed organizzati nel gestire i clienti che gli altri danno ormai per persi, ed essere più propenso a rivalutarvi, d’altronde vi conosce già, conosce il vostro prodotto ed è più confidente.
Quindi impariamo a registrare correttamente i motivi per cui un’opportunità non è stata “vinta” e distinguiamo in maniera molto netta quelle “perse” da quelle “morte” dove non vale la pena investire altro tempo.

Error handling in javascript utilizzando Google Analytics

E’ buona norma avere un log degli errori anche sulle pagine web, specie se si fa uso di librerie javascript come JQuery.

Io ero solito redirigere l’evento window.onerror e scrivere su un backend apposito per registrare l’errore, ma se non si vuole/può realizzarlo?

La soluzione è semplicissima. Si possono registrare gli errori in Google Analytics insieme alle statistiche sulle visite del sito. Un ottimo modo per venirne a capo no?

window.onerror = function(message, file, line) {
   _gaq.push(['_trackEvent', 'JS Error', file + ':' + line + '\n\n' + message]);
};

https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide?hl=it

Due giorni tra XML e JSON

Approfittando di questi giorni estivi, mi sono dedicato a “testare” alcune idee che mi frullavano per la testa da tempo.

In particolare volevo convertire parte della struttura dell’ App Mobile di Tustena da XML in Json per risparmiare un pò di spazio nel DB e vedere se aumentavano le performance.

Per fare ciò ho scritto delle funzioni che mantenessero parzialmente la compatibilità del codice, visto che gli schemi rimangono comunque in XML.

L’esperimenti è fallito perchè a livello di performance non c’erano miglioramenti, e la mancanza degli attributi ha compromesso parte delle funzionalità.

Quindi rimane così com’è, ma condivido le funzioni di conversione che sono alquanto interessanti, specie quella di compatibilità tra la sintassi xPath di XML come pseudo-selettore in Json.

Sviluppo Agile con Tustena CRM e PivotalTracker

Sono sempre stato un fun dello sviluppo Agile-Scrum e da tempo sto portando avanti una mia web application per gestire questo tipo di progetti.

Purtroppo il tempo da dedicargli e poco, e procede troppo a rilento.

Mi sono quindi guardato in giro e ritengo che tra gli strumenti web più adatti a questo scopo ci si PivotalTracker.

Ho provato ad utilizzarlo per gestire le assegnazioni sulle customizzazioni di Tustena CRM, e devo dire che la piattaforma è molto ben fatta anche se mancano alcune cose che nel mio progetto ritenevo fondamentali e che prima o poi me lo faranno riprendere in mano. 

Comunque per poterlo utilizzare in modo strutturato non potevo pensare di procedere di copia incolla tra i ticket aperti in Tustena CRM e le story in PivotalTracker, quindi ho scritto un connettore per il CRM e l’integrazione risulta particolarmente comoda.

Per chi volesse utilizzarlo, allego il file da inserire nella directory ticket di Tustena CRM. Basterà quindi chiamarlo da PivotalTracker, dopo aver configurato le impostazioni di integrazione per trovarsi magicamente i bug anche sul tracker.

Si può fare anche di meglio passando i dati indietro, ma a quanto pare i ragazzi di PivotalTracker non hanno pensato di esporre l’ExternalId nei WebHook, quindi per il momento non ci sono soluzioni eleganti per gestire il ritorno.

pivotalservice.aspx (4,17 kb)

CRM lifecycle: Quando il software conta

Il mercato è costellato di progetti CRM abbandonati e implementazioni lasciate a metà. In molti casi questa disaffezione ha origine dalla mancanza di volontà da parte dei singoli e da una strategia aziendale confusa, ricca di aspettative ma senza un vero piano operativo.

Però tante volete il problema è la mancanza di budget, che fa ridurre l’investimento in analisi e avviamento, o peggio, fa rinunciare ad una corretta implementazione della piattaforma, obbligando gli utenti ad adattarsi a strumenti inadeguati.

La conseguente macchinosità delle attività di data entry, e degli approcci poco user-friendly diventano l’alibi per bollare il sistema come inutile, complicato e poco remunerativo per chi ci lavora.

D’altronde se gli utenti non lo usano, un CRM serve a ben poco. Perciò è importante allocare una parte del budget per adattare le procedure al modus-operandi dell’azienda, e scegliere un software che sia completo e facile da personalizzare.

Anche il ciclo di vita dell’applicazione deve essere presa seriamente in considerazione, e il fornitore deve garantire la longevità di quanto realizzato e personalizzato, senza richiedere investimenti annuali per riadattare le customizzazioni ai frequenti aggiornamenti della piattaforma.

Sono tutti aspetti comuni al mondo del software aziendale, ma se è vero che ci sono aziende con software ERP vecchi di 20 anni, questo non vale per un CRM, specie se integrato con strumenti cloud e social, dove gli aggiornamenti diventano all’ordine del giorno.